summaryrefslogtreecommitdiff
path: root/ext/opcache
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opcache')
-rw-r--r--ext/opcache/Optimizer/block_pass.c1136
-rw-r--r--ext/opcache/Optimizer/compact_literals.c59
-rw-r--r--ext/opcache/Optimizer/dce.c3
-rw-r--r--ext/opcache/Optimizer/dfa_pass.c113
-rw-r--r--ext/opcache/Optimizer/escape_analysis.c21
-rw-r--r--ext/opcache/Optimizer/optimize_func_calls.c8
-rw-r--r--ext/opcache/Optimizer/optimize_temp_vars_5.c2
-rw-r--r--ext/opcache/Optimizer/pass1.c (renamed from ext/opcache/Optimizer/pass1_5.c)186
-rw-r--r--ext/opcache/Optimizer/pass2.c225
-rw-r--r--ext/opcache/Optimizer/pass3.c563
-rw-r--r--ext/opcache/Optimizer/sccp.c23
-rw-r--r--ext/opcache/Optimizer/ssa_integrity.c2
-rw-r--r--ext/opcache/Optimizer/zend_call_graph.c19
-rw-r--r--ext/opcache/Optimizer/zend_call_graph.h3
-rw-r--r--ext/opcache/Optimizer/zend_cfg.c2
-rw-r--r--ext/opcache/Optimizer/zend_cfg.h9
-rw-r--r--ext/opcache/Optimizer/zend_dfg.c4
-rw-r--r--ext/opcache/Optimizer/zend_dump.c108
-rw-r--r--ext/opcache/Optimizer/zend_dump.h3
-rw-r--r--ext/opcache/Optimizer/zend_func_info.c1538
-rw-r--r--ext/opcache/Optimizer/zend_func_info.h5
-rw-r--r--ext/opcache/Optimizer/zend_inference.c327
-rw-r--r--ext/opcache/Optimizer/zend_inference.h24
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c368
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.h6
-rw-r--r--ext/opcache/Optimizer/zend_optimizer_internal.h3
-rw-r--r--ext/opcache/Optimizer/zend_ssa.c328
-rw-r--r--ext/opcache/Optimizer/zend_ssa.h11
-rw-r--r--ext/opcache/ZendAccelerator.c224
-rw-r--r--ext/opcache/ZendAccelerator.h24
-rw-r--r--ext/opcache/config.m479
-rw-r--r--ext/opcache/config.w3225
-rw-r--r--ext/opcache/jit/Makefile.frag17
-rw-r--r--ext/opcache/jit/Makefile.frag.w3216
-rw-r--r--ext/opcache/jit/dynasm/dasm_arm.h456
-rw-r--r--ext/opcache/jit/dynasm/dasm_arm.lua1125
-rw-r--r--ext/opcache/jit/dynasm/dasm_arm64.h518
-rw-r--r--ext/opcache/jit/dynasm/dasm_arm64.lua1166
-rw-r--r--ext/opcache/jit/dynasm/dasm_mips.h419
-rw-r--r--ext/opcache/jit/dynasm/dasm_mips.lua1008
-rw-r--r--ext/opcache/jit/dynasm/dasm_mips64.lua12
-rw-r--r--ext/opcache/jit/dynasm/dasm_ppc.h419
-rw-r--r--ext/opcache/jit/dynasm/dasm_ppc.lua1919
-rw-r--r--ext/opcache/jit/dynasm/dasm_proto.h83
-rw-r--r--ext/opcache/jit/dynasm/dasm_x64.lua12
-rw-r--r--ext/opcache/jit/dynasm/dasm_x86.h500
-rw-r--r--ext/opcache/jit/dynasm/dasm_x86.lua2274
-rw-r--r--ext/opcache/jit/dynasm/dynasm.lua1094
-rw-r--r--ext/opcache/jit/dynasm/minilua.c7770
-rw-r--r--ext/opcache/jit/libudis86/LICENSE22
-rw-r--r--ext/opcache/jit/libudis86/decode.c1266
-rw-r--r--ext/opcache/jit/libudis86/decode.h197
-rw-r--r--ext/opcache/jit/libudis86/extern.h113
-rw-r--r--ext/opcache/jit/libudis86/itab.c5946
-rw-r--r--ext/opcache/jit/libudis86/itab.h939
-rw-r--r--ext/opcache/jit/libudis86/syn-att.c228
-rw-r--r--ext/opcache/jit/libudis86/syn-intel.c224
-rw-r--r--ext/opcache/jit/libudis86/syn.c258
-rw-r--r--ext/opcache/jit/libudis86/syn.h53
-rw-r--r--ext/opcache/jit/libudis86/types.h260
-rw-r--r--ext/opcache/jit/libudis86/udint.h99
-rw-r--r--ext/opcache/jit/libudis86/udis86.c458
-rw-r--r--ext/opcache/jit/vtune/ittnotify_config.h596
-rw-r--r--ext/opcache/jit/vtune/ittnotify_types.h115
-rw-r--r--ext/opcache/jit/vtune/jitprofiling.c312
-rw-r--r--ext/opcache/jit/vtune/jitprofiling.h694
-rw-r--r--ext/opcache/jit/zend_elf.c109
-rw-r--r--ext/opcache/jit/zend_elf.h115
-rw-r--r--ext/opcache/jit/zend_jit.c3652
-rw-r--r--ext/opcache/jit/zend_jit.h109
-rw-r--r--ext/opcache/jit/zend_jit_disasm_x86.c519
-rw-r--r--ext/opcache/jit/zend_jit_gdb.c493
-rw-r--r--ext/opcache/jit/zend_jit_helpers.c1504
-rw-r--r--ext/opcache/jit/zend_jit_internal.h119
-rw-r--r--ext/opcache/jit/zend_jit_oprofile.c50
-rw-r--r--ext/opcache/jit/zend_jit_perf_dump.c246
-rw-r--r--ext/opcache/jit/zend_jit_vm_helpers.c268
-rw-r--r--ext/opcache/jit/zend_jit_vtune.c42
-rw-r--r--ext/opcache/jit/zend_jit_x86.dasc9827
-rw-r--r--ext/opcache/jit/zend_jit_x86.h309
-rw-r--r--ext/opcache/opcache.stub.php13
-rw-r--r--ext/opcache/opcache_arginfo.h24
-rw-r--r--ext/opcache/shared_alloc_mmap.c62
-rw-r--r--ext/opcache/shared_alloc_win32.c30
-rw-r--r--ext/opcache/tests/assign_obj_op_of_fetch_dim.phpt12
-rw-r--r--ext/opcache/tests/blacklist.inc2
-rw-r--r--ext/opcache/tests/block_pass_001.phpt2
-rw-r--r--ext/opcache/tests/bool_not_cv.phpt4
-rw-r--r--ext/opcache/tests/bug64353.phpt20
-rw-r--r--ext/opcache/tests/bug65665.phpt168
-rw-r--r--ext/opcache/tests/bug66176.phpt4
-rw-r--r--ext/opcache/tests/bug66251.phpt9
-rw-r--r--ext/opcache/tests/bug66334.phpt4
-rw-r--r--ext/opcache/tests/bug66338.phpt22
-rw-r--r--ext/opcache/tests/bug66440.phpt2
-rw-r--r--ext/opcache/tests/bug66474.phpt2
-rw-r--r--ext/opcache/tests/bug68252.phpt21
-rw-r--r--ext/opcache/tests/bug68644.phpt17
-rw-r--r--ext/opcache/tests/bug69038.phpt58
-rw-r--r--ext/opcache/tests/bug69159.phpt2
-rw-r--r--ext/opcache/tests/bug70207.phpt6
-rw-r--r--ext/opcache/tests/bug71843.phpt9
-rw-r--r--ext/opcache/tests/bug73402.phpt18
-rw-r--r--ext/opcache/tests/bug73583.phpt6
-rw-r--r--ext/opcache/tests/bug73668.phpt2
-rw-r--r--ext/opcache/tests/bug73746.phpt24
-rw-r--r--ext/opcache/tests/bug73789.phpt40
-rw-r--r--ext/opcache/tests/bug74019.phpt12
-rw-r--r--ext/opcache/tests/bug74152.phpt10
-rw-r--r--ext/opcache/tests/bug74456.phpt2
-rw-r--r--ext/opcache/tests/bug74596.phpt32
-rw-r--r--ext/opcache/tests/bug74980.phpt18
-rw-r--r--ext/opcache/tests/bug75230.phpt4
-rw-r--r--ext/opcache/tests/bug75357.phpt26
-rw-r--r--ext/opcache/tests/bug75370.phpt6
-rw-r--r--ext/opcache/tests/bug75556.phpt14
-rw-r--r--ext/opcache/tests/bug75687.phpt6
-rw-r--r--ext/opcache/tests/bug75729.phpt21
-rw-r--r--ext/opcache/tests/bug75893.phpt24
-rw-r--r--ext/opcache/tests/bug75938.phpt10
-rw-r--r--ext/opcache/tests/bug76074.phpt4
-rw-r--r--ext/opcache/tests/bug76094.phpt14
-rw-r--r--ext/opcache/tests/bug76446.phpt8
-rw-r--r--ext/opcache/tests/bug76463.phpt2
-rw-r--r--ext/opcache/tests/bug76477.phpt6
-rw-r--r--ext/opcache/tests/bug77058.phpt4
-rw-r--r--ext/opcache/tests/bug77191.phpt14
-rw-r--r--ext/opcache/tests/bug77266.phpt24
-rw-r--r--ext/opcache/tests/bug77743.phpt12
-rw-r--r--ext/opcache/tests/bug78014.inc2
-rw-r--r--ext/opcache/tests/bug78015.phpt2
-rw-r--r--ext/opcache/tests/bug78185.phpt6
-rw-r--r--ext/opcache/tests/bug78986.phpt2
-rw-r--r--ext/opcache/tests/compact_literals.phpt72
-rw-r--r--ext/opcache/tests/issue0115.phpt1
-rw-r--r--ext/opcache/tests/issue0140.phpt1
-rw-r--r--ext/opcache/tests/issue0149.phpt1
-rw-r--r--ext/opcache/tests/issue0183.phpt18
-rw-r--r--ext/opcache/tests/jit/array_elem.phpt28
-rw-r--r--ext/opcache/tests/jit/assign_001.phpt27
-rw-r--r--ext/opcache/tests/jit/assign_002.phpt29
-rw-r--r--ext/opcache/tests/jit/assign_003.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_004.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_005.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_006.phpt22
-rw-r--r--ext/opcache/tests/jit/assign_007.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_008.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_009.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_010.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_011.phpt28
-rw-r--r--ext/opcache/tests/jit/assign_012.phpt28
-rw-r--r--ext/opcache/tests/jit/assign_013.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_014.phpt22
-rw-r--r--ext/opcache/tests/jit/assign_015.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_016.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_017.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_018.phpt26
-rw-r--r--ext/opcache/tests/jit/assign_019.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_020.phpt22
-rw-r--r--ext/opcache/tests/jit/assign_021.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_022.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_023.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_024.phpt23
-rw-r--r--ext/opcache/tests/jit/assign_025.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_026.phpt25
-rw-r--r--ext/opcache/tests/jit/assign_027.phpt22
-rw-r--r--ext/opcache/tests/jit/assign_028.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_029.phpt22
-rw-r--r--ext/opcache/tests/jit/assign_030.phpt23
-rw-r--r--ext/opcache/tests/jit/assign_031.phpt19
-rw-r--r--ext/opcache/tests/jit/assign_032.phpt27
-rw-r--r--ext/opcache/tests/jit/assign_033.phpt24
-rw-r--r--ext/opcache/tests/jit/assign_034.phpt21
-rw-r--r--ext/opcache/tests/jit/assign_035.phpt39
-rw-r--r--ext/opcache/tests/jit/assign_036.phpt43
-rw-r--r--ext/opcache/tests/jit/assign_dim_002.phpt137
-rw-r--r--ext/opcache/tests/jit/bug77857.phpt27
-rw-r--r--ext/opcache/tests/jit/cmp_001.phpt24
-rw-r--r--ext/opcache/tests/jit/cmp_002.phpt24
-rw-r--r--ext/opcache/tests/jit/cmp_003.phpt194
-rw-r--r--ext/opcache/tests/jit/cmp_004.phpt22
-rw-r--r--ext/opcache/tests/jit/const_001.phpt26
-rw-r--r--ext/opcache/tests/jit/defined_001.phpt38
-rw-r--r--ext/opcache/tests/jit/fetch_dim_func_args_001.phpt26
-rw-r--r--ext/opcache/tests/jit/fetch_dim_r_001.phpt45
-rw-r--r--ext/opcache/tests/jit/fetch_dim_r_002.phpt45
-rw-r--r--ext/opcache/tests/jit/fetch_dim_r_003.phpt61
-rw-r--r--ext/opcache/tests/jit/fetch_dim_r_004.phpt61
-rw-r--r--ext/opcache/tests/jit/fetch_dim_rw_001.phpt27
-rw-r--r--ext/opcache/tests/jit/fetch_obj_001.phpt137
-rw-r--r--ext/opcache/tests/jit/fetch_obj_002.phpt41
-rw-r--r--ext/opcache/tests/jit/fetch_obj_003.phpt46
-rw-r--r--ext/opcache/tests/jit/fetch_obj_004.phpt43
-rw-r--r--ext/opcache/tests/jit/inc_001.phpt22
-rw-r--r--ext/opcache/tests/jit/inc_002.phpt21
-rw-r--r--ext/opcache/tests/jit/inc_003.phpt22
-rw-r--r--ext/opcache/tests/jit/inc_004.phpt21
-rw-r--r--ext/opcache/tests/jit/inc_005.phpt23
-rw-r--r--ext/opcache/tests/jit/inc_006.phpt22
-rw-r--r--ext/opcache/tests/jit/inc_007.phpt21
-rw-r--r--ext/opcache/tests/jit/inc_008.phpt20
-rw-r--r--ext/opcache/tests/jit/inc_009.phpt22
-rw-r--r--ext/opcache/tests/jit/inc_010.phpt21
-rw-r--r--ext/opcache/tests/jit/inc_011.phpt22
-rw-r--r--ext/opcache/tests/jit/inc_012.phpt21
-rw-r--r--ext/opcache/tests/jit/inc_013.phpt23
-rw-r--r--ext/opcache/tests/jit/inc_014.phpt22
-rw-r--r--ext/opcache/tests/jit/inc_015.phpt21
-rw-r--r--ext/opcache/tests/jit/inc_016.phpt20
-rw-r--r--ext/opcache/tests/jit/inc_017.phpt20
-rw-r--r--ext/opcache/tests/jit/inc_018.phpt20
-rw-r--r--ext/opcache/tests/jit/inc_019.phpt27
-rw-r--r--ext/opcache/tests/jit/inc_020.phpt28
-rw-r--r--ext/opcache/tests/jit/jmpz_001.phpt26
-rw-r--r--ext/opcache/tests/jit/jmpz_ex_001.phpt32
-rw-r--r--ext/opcache/tests/jit/mod_001.phpt41
-rw-r--r--ext/opcache/tests/jit/mod_002.phpt53
-rw-r--r--ext/opcache/tests/jit/noval_001.phpt34
-rw-r--r--ext/opcache/tests/jit/recv_001.phpt23
-rw-r--r--ext/opcache/tests/jit/reg_alloc_001.phpt39
-rw-r--r--ext/opcache/tests/jit/reg_alloc_002.phpt28
-rw-r--r--ext/opcache/tests/jit/reg_alloc_003.phpt23
-rw-r--r--ext/opcache/tests/jit/send_val_001.phpt23
-rw-r--r--ext/opcache/tests/jit/send_var_ex_001.phpt30
-rw-r--r--ext/opcache/tests/jit/shift_left_001.phpt37
-rw-r--r--ext/opcache/tests/jit/shift_left_002.phpt49
-rw-r--r--ext/opcache/tests/jit/shift_right_001.phpt43
-rw-r--r--ext/opcache/tests/jit/shift_right_002.phpt55
-rw-r--r--ext/opcache/tests/jit/shift_right_003.phpt26
-rw-r--r--ext/opcache/tests/jit/skipif.inc3
-rw-r--r--ext/opcache/tests/jit/switch_jumptable.phpt40
-rw-r--r--ext/opcache/tests/jit/type_check_001.phpt25
-rw-r--r--ext/opcache/tests/jit/unreachable_block.phpt25
-rw-r--r--ext/opcache/tests/jmpz_jmp_elim.phpt2
-rw-r--r--ext/opcache/tests/opt/block_pass_001.phpt24
-rw-r--r--ext/opcache/tests/opt/block_pass_002.phpt19
-rw-r--r--ext/opcache/tests/opt/dce_001.phpt6
-rw-r--r--ext/opcache/tests/opt/dce_002.phpt12
-rw-r--r--ext/opcache/tests/opt/dce_003.phpt4
-rw-r--r--ext/opcache/tests/opt/dce_004.phpt8
-rw-r--r--ext/opcache/tests/opt/dce_005.phpt4
-rw-r--r--ext/opcache/tests/opt/dce_006.phpt6
-rw-r--r--ext/opcache/tests/opt/sccp_001.phpt8
-rw-r--r--ext/opcache/tests/opt/sccp_002.phpt22
-rw-r--r--ext/opcache/tests/opt/sccp_003.phpt22
-rw-r--r--ext/opcache/tests/opt/sccp_004.phpt24
-rw-r--r--ext/opcache/tests/opt/sccp_005.phpt6
-rw-r--r--ext/opcache/tests/opt/sccp_006.phpt4
-rw-r--r--ext/opcache/tests/opt/sccp_007.phpt14
-rw-r--r--ext/opcache/tests/opt/sccp_008.phpt12
-rw-r--r--ext/opcache/tests/opt/sccp_009.phpt8
-rw-r--r--ext/opcache/tests/opt/sccp_010.phpt20
-rw-r--r--ext/opcache/tests/opt/sccp_011.phpt20
-rw-r--r--ext/opcache/tests/opt/sccp_012.phpt24
-rw-r--r--ext/opcache/tests/opt/sccp_013.phpt10
-rw-r--r--ext/opcache/tests/opt/sccp_014.phpt12
-rw-r--r--ext/opcache/tests/opt/sccp_015.phpt16
-rw-r--r--ext/opcache/tests/opt/sccp_017.phpt12
-rw-r--r--ext/opcache/tests/opt/sccp_018.phpt14
-rw-r--r--ext/opcache/tests/opt/sccp_019.phpt10
-rw-r--r--ext/opcache/tests/opt/sccp_020.phpt12
-rw-r--r--ext/opcache/tests/opt/sccp_021.phpt22
-rw-r--r--ext/opcache/tests/opt/sccp_022.phpt14
-rw-r--r--ext/opcache/tests/opt/sccp_023.phpt12
-rw-r--r--ext/opcache/tests/opt/sccp_024.phpt6
-rw-r--r--ext/opcache/tests/opt/sccp_025.phpt42
-rw-r--r--ext/opcache/tests/opt/sccp_026.phpt2
-rw-r--r--ext/opcache/tests/opt/sccp_027.phpt18
-rw-r--r--ext/opcache/tests/opt/sccp_029.phpt2
-rw-r--r--ext/opcache/tests/opt/sccp_031.phpt36
-rw-r--r--ext/opcache/tests/optimize_func_calls.phpt18
-rw-r--r--ext/opcache/tests/optimize_static_001.phpt12
-rw-r--r--ext/opcache/tests/phi_remove_001.phpt96
-rw-r--r--ext/opcache/tests/phi_remove_002.phpt10
-rw-r--r--ext/opcache/tests/php_cli_server.inc106
-rw-r--r--ext/opcache/tests/preload.inc36
-rw-r--r--ext/opcache/tests/preload_009.phpt6
-rw-r--r--ext/opcache/tests/preload_011.phpt2
-rw-r--r--ext/opcache/tests/preload_012.phpt2
-rw-r--r--ext/opcache/tests/preload_bug78014.inc2
-rw-r--r--ext/opcache/tests/preload_bug78175_2.inc22
-rw-r--r--ext/opcache/tests/preload_bug78376.inc2
-rw-r--r--ext/opcache/tests/preload_bug78937.inc4
-rw-r--r--ext/opcache/tests/preload_globals.inc2
-rw-r--r--ext/opcache/tests/preload_loadable_classes_2.phpt4
-rw-r--r--ext/opcache/tests/revalidate_path_01.phpt29
-rw-r--r--ext/opcache/tests/ssa_bug_001.phpt2
-rw-r--r--ext/opcache/tests/ssa_bug_007.phpt24
-rw-r--r--ext/opcache/tests/ssa_bug_011.phpt10
-rw-r--r--ext/opcache/tests/wrong_inlining_002.phpt9
-rw-r--r--ext/opcache/tests/wrong_inlining_003.phpt2
-rw-r--r--ext/opcache/tests/wrong_inlining_004.phpt2
-rw-r--r--ext/opcache/zend_accelerator_debug.c2
-rw-r--r--ext/opcache/zend_accelerator_module.c65
-rw-r--r--ext/opcache/zend_accelerator_util_funcs.c21
-rw-r--r--ext/opcache/zend_file_cache.c65
-rw-r--r--ext/opcache/zend_persist.c92
-rw-r--r--ext/opcache/zend_persist_calc.c44
-rw-r--r--ext/opcache/zend_shared_alloc.c33
-rw-r--r--ext/opcache/zend_shared_alloc.h7
300 files changed, 54557 insertions, 4061 deletions
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index 3327ec86df..baf01bbb36 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -33,51 +33,33 @@
/* Checks if a constant (like "true") may be replaced by its value */
int zend_optimizer_get_persistent_constant(zend_string *name, zval *result, int copy)
{
- zend_constant *c;
- char *lookup_name;
- int retval = 1;
- ALLOCA_FLAG(use_heap);
-
- if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
- lookup_name = do_alloca(ZSTR_LEN(name) + 1, use_heap);
- memcpy(lookup_name, ZSTR_VAL(name), ZSTR_LEN(name) + 1);
- zend_str_tolower(lookup_name, ZSTR_LEN(name));
-
- if ((c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, ZSTR_LEN(name))) != NULL) {
- if (!(ZEND_CONSTANT_FLAGS(c) & CONST_CT_SUBST) || (ZEND_CONSTANT_FLAGS(c) & CONST_CS)) {
- retval = 0;
- }
- } else {
- retval = 0;
- }
- free_alloca(lookup_name, use_heap);
- }
-
- if (retval) {
+ zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name);
+ if (c) {
if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)
+ && !(ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED)
&& (!(ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE)
|| !(CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
ZVAL_COPY_VALUE(result, &c->value);
if (copy) {
Z_TRY_ADDREF_P(result);
}
+ return 1;
} else {
- retval = 0;
+ return 0;
}
}
- return retval;
+ /* Special constants null/true/false can always be substituted. */
+ c = zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name));
+ if (c) {
+ ZVAL_COPY_VALUE(result, &c->value);
+ return 1;
+ }
+ return 0;
}
-/* CFG back references management */
-
-#define DEL_SOURCE(from, to)
-#define ADD_SOURCE(from, to)
-
/* Data dependencies macros */
-#define VAR_NUM_EX(op) VAR_NUM((op).var)
-
#define VAR_SOURCE(op) Tsource[VAR_NUM(op.var)]
#define SET_VAR_SOURCE(opline) Tsource[VAR_NUM(opline->result.var)] = opline
@@ -86,15 +68,6 @@ static void strip_leading_nops(zend_op_array *op_array, zend_basic_block *b)
zend_op *opcodes = op_array->opcodes;
do {
- /* check if NOP breaks incorrect smart branch */
- if (b->len == 2
- && (opcodes[b->start + 1].opcode == ZEND_JMPZ
- || opcodes[b->start + 1].opcode == ZEND_JMPNZ)
- && (opcodes[b->start + 1].op1_type & (IS_CV|IS_CONST))
- && b->start > 0
- && zend_is_smart_branch(opcodes + b->start - 1)) {
- break;
- }
b->start++;
b->len--;
} while (b->len > 0 && opcodes[b->start].opcode == ZEND_NOP);
@@ -125,14 +98,6 @@ static void strip_nops(zend_op_array *op_array, zend_basic_block *b)
}
j++;
}
- if (i + 1 < b->start + b->len
- && (op_array->opcodes[i+1].opcode == ZEND_JMPZ
- || op_array->opcodes[i+1].opcode == ZEND_JMPNZ)
- && op_array->opcodes[i+1].op1_type & (IS_CV|IS_CONST)
- && zend_is_smart_branch(op_array->opcodes + j - 1)) {
- /* don't remove NOP, that splits incorrect smart branch */
- j++;
- }
i++;
}
b->len = j - b->start;
@@ -203,52 +168,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
literal_dtor(&ZEND_OP1_LITERAL(src));
MAKE_NOP(src);
++(*opt_count);
- switch (opline->opcode) {
- case ZEND_JMPZ:
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- MAKE_NOP(opline);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
- } else {
- opline->opcode = ZEND_JMP;
- COPY_NODE(opline->op1, opline->op2);
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
- }
- break;
- case ZEND_JMPNZ:
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- opline->opcode = ZEND_JMP;
- COPY_NODE(opline->op1, opline->op2);
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
- } else {
- MAKE_NOP(opline);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
- }
- break;
- case ZEND_JMPZNZ:
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = block->successors[1];
- } else {
- zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
- DEL_SOURCE(block, block->successors[0]);
- }
- block->successors_count = 1;
- opline->op1_type = IS_UNUSED;
- opline->extended_value = 0;
- opline->opcode = ZEND_JMP;
- break;
- default:
- break;
- }
} else {
zval_ptr_dtor_nogc(&c);
}
@@ -278,75 +197,91 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
}
}
- if (opline->opcode == ZEND_ECHO) {
- if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
- src = VAR_SOURCE(opline->op1);
- if (src &&
- src->opcode == ZEND_CAST &&
- src->extended_value == IS_STRING) {
- /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
- VAR_SOURCE(opline->op1) = NULL;
- COPY_NODE(opline->op1, src->op1);
- MAKE_NOP(src);
- ++(*opt_count);
- }
- }
-
- if (opline->op1_type == IS_CONST) {
- if (last_op && last_op->opcode == ZEND_ECHO &&
- last_op->op1_type == IS_CONST &&
- Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE &&
- Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_DOUBLE) {
- /* compress consecutive ECHO's.
- * Float to string conversion may be affected by current
- * locale setting.
- */
- int l, old_len;
-
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP1_LITERAL(opline));
- }
- if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
- convert_to_string(&ZEND_OP1_LITERAL(last_op));
+ switch (opline->opcode) {
+ case ZEND_ECHO:
+ if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
+ src = VAR_SOURCE(opline->op1);
+ if (src &&
+ src->opcode == ZEND_CAST &&
+ src->extended_value == IS_STRING) {
+ /* T = CAST(X, String), ECHO(T) => NOP, ECHO(X) */
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
}
- old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
- l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
- if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
- zend_string *tmp = zend_string_alloc(l, 0);
- memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
- Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
- } else {
- Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
+ } else if (opline->op1_type == IS_CONST &&
+ Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_DOUBLE) {
+ if (last_op == opline - 1) {
+ /* compress consecutive ECHO's.
+ * Float to string conversion may be affected by current
+ * locale setting.
+ */
+ int l, old_len;
+
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP1_LITERAL(opline));
+ }
+ if (Z_TYPE(ZEND_OP1_LITERAL(last_op)) != IS_STRING) {
+ convert_to_string(&ZEND_OP1_LITERAL(last_op));
+ }
+ old_len = Z_STRLEN(ZEND_OP1_LITERAL(last_op));
+ l = old_len + Z_STRLEN(ZEND_OP1_LITERAL(opline));
+ if (!Z_REFCOUNTED(ZEND_OP1_LITERAL(last_op))) {
+ zend_string *tmp = zend_string_alloc(l, 0);
+ memcpy(ZSTR_VAL(tmp), Z_STRVAL(ZEND_OP1_LITERAL(last_op)), old_len);
+ Z_STR(ZEND_OP1_LITERAL(last_op)) = tmp;
+ } else {
+ Z_STR(ZEND_OP1_LITERAL(last_op)) = zend_string_extend(Z_STR(ZEND_OP1_LITERAL(last_op)), l, 0);
+ }
+ Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
+ memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
+ Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
+ ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
+ MAKE_NOP(last_op);
+ ++(*opt_count);
}
- Z_TYPE_INFO(ZEND_OP1_LITERAL(last_op)) = IS_STRING_EX;
- memcpy(Z_STRVAL(ZEND_OP1_LITERAL(last_op)) + old_len, Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)));
- Z_STRVAL(ZEND_OP1_LITERAL(last_op))[l] = '\0';
- zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
- ZVAL_STR(&ZEND_OP1_LITERAL(opline), zend_new_interned_string(Z_STR(ZEND_OP1_LITERAL(last_op))));
- ZVAL_NULL(&ZEND_OP1_LITERAL(last_op));
- MAKE_NOP(last_op);
- ++(*opt_count);
+ last_op = opline;
}
- last_op = opline;
- } else {
- last_op = NULL;
- }
- } else {
- last_op = NULL;
- }
-
- switch (opline->opcode) {
+ break;
case ZEND_FREE:
if (opline->op1_type == IS_TMP_VAR) {
src = VAR_SOURCE(opline->op1);
- if (src &&
- (src->opcode == ZEND_BOOL || src->opcode == ZEND_BOOL_NOT)) {
- /* T = BOOL(X), FREE(T) => T = BOOL(X) */
- /* The remaining BOOL is removed by a separate optimization */
- VAR_SOURCE(opline->op1) = NULL;
- MAKE_NOP(opline);
- ++(*opt_count);
+ if (src) {
+ switch (src->opcode) {
+ case ZEND_BOOL:
+ case ZEND_BOOL_NOT:
+ /* T = BOOL(X), FREE(T) => T = BOOL(X) */
+ /* The remaining BOOL is removed by a separate optimization */
+ VAR_SOURCE(opline->op1) = NULL;
+ MAKE_NOP(opline);
+ ++(*opt_count);
+ break;
+ case ZEND_ASSIGN:
+ case ZEND_ASSIGN_DIM:
+ case ZEND_ASSIGN_OBJ:
+ case ZEND_ASSIGN_STATIC_PROP:
+ case ZEND_ASSIGN_OP:
+ case ZEND_ASSIGN_DIM_OP:
+ case ZEND_ASSIGN_OBJ_OP:
+ case ZEND_ASSIGN_STATIC_PROP_OP:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_PRE_INC_STATIC_PROP:
+ case ZEND_PRE_DEC_STATIC_PROP:
+ src->result_type = IS_UNUSED;
+ VAR_SOURCE(opline->op1) = NULL;
+ MAKE_NOP(opline);
+ ++(*opt_count);
+ break;
+ default:
+ break;
+ }
}
} else if (opline->op1_type == IS_VAR) {
src = VAR_SOURCE(opline->op1);
@@ -360,6 +295,13 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
src->result_type = IS_UNUSED;
MAKE_NOP(opline);
++(*opt_count);
+ if (src->opcode == ZEND_QM_ASSIGN) {
+ if (src->op1_type & (IS_VAR|IS_TMP_VAR)) {
+ src->opcode = ZEND_FREE;
+ } else {
+ MAKE_NOP(src);
+ }
+ }
}
}
break;
@@ -592,6 +534,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
MAKE_NOP(opline);
++(*opt_count);
break;
+ case ZEND_ISSET_ISEMPTY_CV:
case ZEND_ISSET_ISEMPTY_VAR:
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
@@ -600,6 +543,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
case ZEND_TYPE_CHECK:
case ZEND_DEFINED:
case ZEND_IN_ARRAY:
+ case ZEND_ARRAY_KEY_EXISTS:
if (opline->opcode == ZEND_BOOL_NOT) {
break;
}
@@ -615,56 +559,135 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
case ZEND_JMPZ:
case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMPZNZ:
- optimize_jmpznz:
- if (opline->op1_type == IS_TMP_VAR &&
- (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
- (opline->result_type == opline->op1_type &&
- opline->result.var == opline->op1.var))) {
- src = VAR_SOURCE(opline->op1);
- if (src) {
- if (src->opcode == ZEND_BOOL_NOT &&
- opline->opcode != ZEND_JMPZ_EX &&
- opline->opcode != ZEND_JMPNZ_EX) {
- VAR_SOURCE(opline->op1) = NULL;
- COPY_NODE(opline->op1, src->op1);
- if (opline->opcode == ZEND_JMPZ) {
+ while (1) {
+ if (opline->op1_type == IS_CONST) {
+ ++(*opt_count);
+ block->successors_count = 1;
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline)) ==
+ (opline->opcode == ZEND_JMPZ)) {
+
+ MAKE_NOP(opline);
+ block->successors[0] = block->successors[1];
+ block->len--;
+ cfg->blocks[block->successors[0]].flags |= ZEND_BB_FOLLOW;
+ break;
+ } else {
+ zend_basic_block *next = cfg->blocks + block->successors[1];
+
+ next->flags &= ~ZEND_BB_FOLLOW;
+ if (!(next->flags & (ZEND_BB_TARGET|ZEND_BB_PROTECTED))) {
+ next->flags &= ~ZEND_BB_REACHABLE;
+ }
+ opline->opcode = ZEND_JMP;
+ COPY_NODE(opline->op1, opline->op2);
+ break;
+ }
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
+ src = VAR_SOURCE(opline->op1);
+ if (src) {
+ if (src->opcode == ZEND_BOOL_NOT) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
/* T = BOOL_NOT(X) + JMPZ(T) -> NOP, JMPNZ(X) */
- opline->opcode = ZEND_JMPNZ;
- } else if (opline->opcode == ZEND_JMPNZ) {
- /* T = BOOL_NOT(X) + JMPNZ(T) -> NOP, JMPZ(X) */
- opline->opcode = ZEND_JMPZ;
-#if 0
- } else if (opline->opcode == ZEND_JMPZ_EX) {
- /* T = BOOL_NOT(X) + JMPZ_EX(T) -> NOP, JMPNZ_EX(X) */
- opline->opcode = ZEND_JMPNZ_EX;
- } else if (opline->opcode == ZEND_JMPNZ_EX) {
- /* T = BOOL_NOT(X) + JMPNZ_EX(T) -> NOP, JMPZ_EX(X) */
- opline->opcode = ZEND_JMPZ;
-#endif
- } else {
+ opline->opcode = INV_COND(opline->opcode);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ } else if (src->opcode == ZEND_BOOL ||
+ src->opcode == ZEND_QM_ASSIGN) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case ZEND_JMPZNZ:
+ while (1) {
+ if (opline->op1_type == IS_CONST) {
+ ++(*opt_count);
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
+ zend_op *target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
+ block->successors[0] = block->successors[1];
+ } else {
+ zend_op *target_opline = ZEND_OP2_JMP_ADDR(opline);
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
+ }
+ block->successors_count = 1;
+ opline->op1_type = IS_UNUSED;
+ opline->extended_value = 0;
+ opline->opcode = ZEND_JMP;
+ break;
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
+ src = VAR_SOURCE(opline->op1);
+ if (src) {
+ if (src->opcode == ZEND_BOOL_NOT) {
/* T = BOOL_NOT(X) + JMPZNZ(T,L1,L2) -> NOP, JMPZNZ(X,L2,L1) */
uint32_t tmp;
- ZEND_ASSERT(opline->opcode == ZEND_JMPZNZ);
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
tmp = block->successors[0];
block->successors[0] = block->successors[1];
block->successors[1] = tmp;
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ } else if (src->opcode == ZEND_BOOL ||
+ src->opcode == ZEND_QM_ASSIGN) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
}
- MAKE_NOP(src);
- ++(*opt_count);
- goto optimize_jmpznz;
- } else if (src->opcode == ZEND_BOOL ||
- src->opcode == ZEND_QM_ASSIGN) {
- VAR_SOURCE(opline->op1) = NULL;
- COPY_NODE(opline->op1, src->op1);
- MAKE_NOP(src);
+ }
+ }
+ break;
+ }
+ break;
+
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ while (1) {
+ if (opline->op1_type == IS_CONST) {
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline)) ==
+ (opline->opcode == ZEND_JMPZ_EX)) {
+
++(*opt_count);
- goto optimize_jmpznz;
+ opline->opcode = ZEND_QM_ASSIGN;
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_BOOL(&ZEND_OP1_LITERAL(opline), opline->opcode == ZEND_JMPZ_EX);
+ opline->op2.num = 0;
+ block->successors_count = 1;
+ block->successors[0] = block->successors[1];
+ cfg->blocks[block->successors[0]].flags |= ZEND_BB_FOLLOW;
+ break;
+ }
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ (!zend_bitset_in(used_ext, VAR_NUM(opline->op1.var)) ||
+ opline->result.var == opline->op1.var)) {
+ src = VAR_SOURCE(opline->op1);
+ if (src) {
+ if (src->opcode == ZEND_BOOL ||
+ src->opcode == ZEND_QM_ASSIGN) {
+ VAR_SOURCE(opline->op1) = NULL;
+ COPY_NODE(opline->op1, src->op1);
+ MAKE_NOP(src);
+ ++(*opt_count);
+ continue;
+ }
}
}
+ break;
}
break;
@@ -894,6 +917,23 @@ optimize_const_unary_op:
/* strip T = QM_ASSIGN(T) */
MAKE_NOP(opline);
++(*opt_count);
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ opline->result_type == IS_TMP_VAR &&
+ !zend_bitset_in(used_ext, VAR_NUM(opline->op1.var))) {
+ /* T1 = ..., T2 = QM_ASSIGN(T1) to T2 = ..., NOP */
+ src = VAR_SOURCE(opline->op1);
+ if (src &&
+ src->opcode != ZEND_COPY_TMP &&
+ src->opcode != ZEND_ADD_ARRAY_ELEMENT &&
+ src->opcode != ZEND_ADD_ARRAY_UNPACK &&
+ (src->opcode != ZEND_DECLARE_LAMBDA_FUNCTION ||
+ src == opline -1)) {
+ src->result.var = opline->result.var;
+ VAR_SOURCE(opline->op1) = NULL;
+ VAR_SOURCE(opline->result) = src;
+ MAKE_NOP(opline);
+ ++(*opt_count);
+ }
}
break;
}
@@ -1089,11 +1129,84 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
}
}
-static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, zend_cfg *cfg, zend_uchar *same_t, uint32_t *opt_count)
+static zend_always_inline zend_basic_block *get_target_block(const zend_cfg *cfg, zend_basic_block *block, int n, uint32_t *opt_count)
+{
+ int b;
+ zend_basic_block *target_block = cfg->blocks + block->successors[n];
+
+ if (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED)) {
+ do {
+ b = target_block->successors[0];
+ target_block = cfg->blocks + b;
+ } while (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED));
+ block->successors[n] = b;
+ ++(*opt_count);
+ }
+ return target_block;
+}
+
+static zend_always_inline zend_basic_block *get_follow_block(const zend_cfg *cfg, zend_basic_block *block, int n, uint32_t *opt_count)
+{
+ int b;
+ zend_basic_block *target_block = cfg->blocks + block->successors[n];
+
+ if (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED)) {
+ do {
+ b = target_block->successors[0];
+ target_block = cfg->blocks + b;
+ } while (target_block->len == 0 && !(target_block->flags & ZEND_BB_PROTECTED));
+ block->successors[n] = b;
+ ++(*opt_count);
+ }
+ return target_block;
+}
+
+static zend_always_inline zend_basic_block *get_next_block(const zend_cfg *cfg, zend_basic_block *block)
+{
+ zend_basic_block *next_block = block + 1;
+ zend_basic_block *end = cfg->blocks + cfg->blocks_count;
+
+ while (1) {
+ if (next_block == end) {
+ return NULL;
+ } else if (next_block->flags & ZEND_BB_REACHABLE) {
+ break;
+ }
+ next_block++;
+ }
+ while (next_block->len == 0 && !(next_block->flags & ZEND_BB_PROTECTED)) {
+ next_block = cfg->blocks + next_block->successors[0];
+ }
+ return next_block;
+}
+
+
+/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
+static zend_always_inline int in_hitlist(int target, int *jmp_hitlist, int jmp_hitlist_count)
+{
+ int i;
+
+ for (i = 0; i < jmp_hitlist_count; i++) {
+ if (jmp_hitlist[i] == target) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define CHECK_LOOP(target) \
+ if (EXPECTED(!in_hitlist(target, jmp_hitlist, jmp_hitlist_count))) { \
+ jmp_hitlist[jmp_hitlist_count++] = target; \
+ } else { \
+ break; \
+ }
+
+static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_array, const zend_cfg *cfg, int *jmp_hitlist, uint32_t *opt_count)
{
/* last_op is the last opcode of the current block */
- zend_basic_block *blocks = cfg->blocks;
- zend_op *last_op;
+ zend_basic_block *target_block, *follow_block, *next_block;
+ zend_op *last_op, *target;
+ int next, jmp_hitlist_count;
if (block->len == 0) {
return;
@@ -1102,35 +1215,32 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
last_op = op_array->opcodes + block->start + block->len - 1;
switch (last_op->opcode) {
case ZEND_JMP:
- {
- zend_basic_block *target_block = blocks + block->successors[0];
- zend_op *target = op_array->opcodes + target_block->start;
- int next = (block - blocks) + 1;
-
- while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
- /* find used one */
- next++;
- }
+ jmp_hitlist_count = 0;
- /* JMP(next) -> NOP */
- if (block->successors[0] == next) {
- MAKE_NOP(last_op);
- ++(*opt_count);
- block->len--;
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+ if (target->opcode == ZEND_JMP) {
+ /* JMP L, L: JMP L1 -> JMP L1 */
+ next = target_block->successors[0];
+ } else {
break;
}
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ }
- if (target->opcode == ZEND_JMP &&
- block->successors[0] != target_block->successors[0] &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMP L, L: JMP L1 -> JMP L1 */
- *last_op = *target;
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMPZNZ &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
+ next_block = get_next_block(cfg, block);
+ if (target_block == next_block) {
+ /* JMP(next) -> NOP */
+ MAKE_NOP(last_op);
+ ++(*opt_count);
+ block->len--;
+ } else if (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+ if (target->opcode == ZEND_JMPZNZ) {
/* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
*last_op = *target;
if (last_op->op1_type == IS_CONST) {
@@ -1138,15 +1248,14 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
}
- DEL_SOURCE(block, block->successors[0]);
block->successors_count = 2;
block->successors[0] = target_block->successors[0];
block->successors[1] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ADD_SOURCE(block, block->successors[1]);
++(*opt_count);
+ goto optimize_jmpznz;
} else if ((target->opcode == ZEND_RETURN ||
target->opcode == ZEND_RETURN_BY_REF ||
+ target->opcode == ZEND_GENERATOR_RETURN ||
target->opcode == ZEND_EXIT) &&
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
/* JMP L, L: RETURN to immediate RETURN */
@@ -1156,96 +1265,68 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(last_op));
last_op->op1.constant = zend_optimizer_add_literal(op_array, &zv);
}
- DEL_SOURCE(block, block->successors[0]);
block->successors_count = 0;
++(*opt_count);
-#if 0
- /* Temporarily disabled - see bug #0025274 */
- } else if (0&& block->op1_to != block &&
- block->op1_to != blocks &&
- op_array->last_try_catch == 0 &&
- target->opcode != ZEND_FREE) {
- /* Block Reordering (saves one JMP on each "for" loop iteration)
- * It is disabled for some cases (ZEND_FREE)
- * which may break register allocation.
- */
- zend_bool can_reorder = 0;
- zend_block_source *cs = block->op1_to->sources;
-
- /* the "target" block doesn't had any followed block */
- while(cs) {
- if (cs->from->follow_to == block->op1_to) {
- can_reorder = 0;
- break;
- }
- cs = cs->next;
- }
- if (can_reorder) {
- next = block->op1_to;
- /* the "target" block is not followed by current "block" */
- while (next->follow_to != NULL) {
- if (next->follow_to == block) {
- can_reorder = 0;
- break;
- }
- next = next->follow_to;
- }
- if (can_reorder) {
- zend_basic_block *prev = blocks;
+ }
+ }
+ break;
- while (prev->next != block->op1_to) {
- prev = prev->next;
- }
- prev->next = next->next;
- next->next = block->next;
- block->next = block->op1_to;
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ jmp_hitlist_count = 0;
- block->follow_to = block->op1_to;
- block->op1_to = NULL;
- MAKE_NOP(last_op);
- block->len--;
- if(block->len == 0) {
- /* this block is nothing but NOP now */
- delete_code_block(block, ctx);
- }
- break;
- }
- }
-#endif
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+
+ if (target->opcode == ZEND_JMP) {
+ /* JMP_SET(X, L), L: JMP(L2) -> JMP_SET(X, L2) */
+ next = target_block->successors[0];
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ } else {
+ break;
}
+ target_block = get_target_block(cfg, block, 0, opt_count);
}
break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
- /* constant conditional JMPs */
- if (last_op->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
+ jmp_hitlist_count = 0;
- if (last_op->opcode == ZEND_JMPZ) {
- should_jmp = !should_jmp;
- }
- literal_dtor(&ZEND_OP1_LITERAL(last_op));
- last_op->op1_type = IS_UNUSED;
- if (should_jmp) {
- /* JMPNZ(true) -> JMP */
- last_op->opcode = ZEND_JMP;
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
+
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
+ next = target_block->successors[0];
+ } else if (target->opcode == last_op->opcode &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
+ next = target_block->successors[0];
+ } else if (target->opcode == INV_COND(last_op->opcode) &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
+ next = target_block->successors[1];
+ } else if (target->opcode == ZEND_JMPZNZ &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
+ next = target_block->successors[last_op->opcode == ZEND_JMPNZ];
} else {
- /* JMPNZ(false) -> NOP */
- MAKE_NOP(last_op);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
+ break;
}
+ CHECK_LOOP(next);
+ block->successors[0] = next;
++(*opt_count);
- break;
+ target_block = get_target_block(cfg, block, 0, opt_count);
}
- if (block->successors[0] == block->successors[1]) {
+ follow_block = get_follow_block(cfg, block, 1, opt_count);
+ if (target_block == follow_block) {
/* L: JMP[N]Z(X, L+1) -> NOP or FREE(X) */
-
if (last_op->op1_type == IS_CV) {
last_op->opcode = ZEND_CHECK_VAR;
last_op->op2.num = 0;
@@ -1254,122 +1335,55 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
last_op->op2.num = 0;
} else {
MAKE_NOP(last_op);
+ block->len--;
}
block->successors_count = 1;
++(*opt_count);
- break;
- }
+ } else if (follow_block->len == 1) {
+ target = op_array->opcodes + follow_block->start;
+ if (target->opcode == ZEND_JMP) {
+ if (block->successors[0] == follow_block->successors[0]) {
+ /* JMPZ(X,L1), JMP(L1) -> NOP, JMP(L1) */
+ if (last_op->op1_type == IS_CV) {
+ last_op->opcode = ZEND_CHECK_VAR;
+ last_op->op2.num = 0;
+ } else if (last_op->op1_type & (IS_VAR|IS_TMP_VAR)) {
+ last_op->opcode = ZEND_FREE;
+ last_op->op2.num = 0;
+ } else {
+ MAKE_NOP(last_op);
+ block->len--;
+ }
+ block->successors_count = 1;
+ ++(*opt_count);
+ break;
+ } else if (!(follow_block->flags & (ZEND_BB_TARGET | ZEND_BB_PROTECTED))) {
+ next_block = get_next_block(cfg, follow_block);
- if (1) {
- zend_uchar same_type = last_op->op1_type;
- uint32_t same_var = VAR_NUM_EX(last_op->op1);
- zend_op *target;
- zend_op *target_end;
- zend_basic_block *target_block = blocks + block->successors[0];
+ if (target_block == next_block) {
+ /* JMPZ(X,L1) JMP(L2) L1: -> JMPNZ(X,L2) NOP*/
-next_target:
- target = op_array->opcodes + target_block->start;
- target_end = target + target_block->len;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
+ last_op->opcode = INV_COND(last_op->opcode);
- /* next block is only NOP's */
- if (target == target_end) {
- target_block = blocks + target_block->successors[0];
- ++(*opt_count);
- goto next_target;
- } else if (target->opcode == INV_COND(last_op->opcode) &&
- /* JMPZ(X, L), L: JMPNZ(X, L2) -> JMPZ(X, L+1) */
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)
- ) {
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == INV_COND_EX(last_op->opcode) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: T = JMPNZ_EX(X, L2) -> T = JMPZ_EX(X, L+1) */
- last_op->opcode += 3;
- COPY_NODE(last_op->result, target->result);
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == last_op->opcode &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: JMPZ(X, L2) -> JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMPZNZ &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- if (last_op->opcode == ZEND_JMPZ) {
- block->successors[0] = target_block->successors[0];
- } else {
- block->successors[0] = target_block->successors[1];
- }
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- }
- }
+ block->successors[0] = follow_block->successors[0];
+ block->successors[1] = next_block - cfg->blocks;
- if (last_op->opcode == ZEND_JMPZ || last_op->opcode == ZEND_JMPNZ) {
- zend_op *target;
- zend_op *target_end;
- zend_basic_block *target_block;
+ follow_block->flags &= ~ZEND_BB_REACHABLE;
+ MAKE_NOP(target);
+ follow_block->len = 0;
- while (1) {
- target_block = blocks + block->successors[1];
- target = op_array->opcodes + target_block->start;
- target_end = op_array->opcodes + target_block->start + 1;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
+ next_block->flags |= ZEND_BB_FOLLOW;
- /* next block is only NOP's */
- if (target == target_end && !(target_block->flags & ZEND_BB_PROTECTED)) {
- DEL_SOURCE(block, block->successors[1]);
- block->successors[1] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[1]);
- ++(*opt_count);
- } else {
- break;
+ break;
+ }
}
- }
- /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
- if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- DEL_SOURCE(block, block->successors[1]);
+
+ /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
if (last_op->opcode == ZEND_JMPZ) {
- block->successors[1] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[1]);
+ block->successors[1] = follow_block->successors[0];
} else {
block->successors[1] = block->successors[0];
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
+ block->successors[0] = follow_block->successors[0];
}
last_op->opcode = ZEND_JMPZNZ;
++(*opt_count);
@@ -1379,212 +1393,153 @@ next_target:
case ZEND_JMPNZ_EX:
case ZEND_JMPZ_EX:
- /* constant conditional JMPs */
- if (last_op->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(last_op));
-
- if (last_op->opcode == ZEND_JMPZ_EX) {
- should_jmp = !should_jmp;
- }
- if (!should_jmp) {
- /* T = JMPZ_EX(true,L) -> T = QM_ASSIGN(true)
- * T = JMPNZ_EX(false,L) -> T = QM_ASSIGN(false)
- */
- last_op->opcode = ZEND_QM_ASSIGN;
- SET_UNUSED(last_op->op2);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
- ++(*opt_count);
- }
- break;
- }
-
- if (1) {
- zend_op *target, *target_end;
- zend_basic_block *target_block;
- int var_num = op_array->last_var + op_array->T;
+ jmp_hitlist_count = 0;
- if (var_num <= 0) {
- return;
- }
- memset(same_t, 0, var_num);
- same_t[VAR_NUM_EX(last_op->op1)] |= last_op->op1_type;
- same_t[VAR_NUM_EX(last_op->result)] |= last_op->result_type;
- target_block = blocks + block->successors[0];
-next_target_ex:
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
target = op_array->opcodes + target_block->start;
- target_end = target + target_block->len;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
- /* next block is only NOP's */
- if (target == target_end) {
- target_block = blocks + target_block->successors[0];
- ++(*opt_count);
- goto next_target_ex;
+
+ if (target->opcode == ZEND_JMP) {
+ /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
+ next = target_block->successors[0];
} else if (target->opcode == last_op->opcode-3 &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
/* T = JMPZ_EX(X, L1), L1: JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == INV_EX_COND(last_op->opcode) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == INV_EX_COND_EX(last_op->opcode) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- (same_t[VAR_NUM_EX(target->result)] & target->result_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX(T, L2) -> T = JMPZ_EX(X, L1+1) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
+ next = target_block->successors[0];
} else if (target->opcode == last_op->opcode &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- (same_t[VAR_NUM_EX(target->result)] & target->result_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L1), L1: T = JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = JMPZ(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
+ target->result.var == last_op->result.var &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* T = JMPZ_EX(X, L1), L1: T = JMPZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L2) */
+ next = target_block->successors[0];
} else if (target->opcode == ZEND_JMPZNZ &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- (same_t[VAR_NUM_EX(target->op1)] & target->op1_type) != 0 &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
/* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, L2, L3) -> T = JMPZ_EX(X, L2) */
- DEL_SOURCE(block, block->successors[0]);
- if (last_op->opcode == ZEND_JMPZ_EX) {
- block->successors[0] = target_block->successors[0];
- } else {
- block->successors[0] = target_block->successors[1];
- }
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
+ next = target_block->successors[last_op->opcode == ZEND_JMPNZ_EX];
+ } else if (target->opcode == INV_EX_COND(last_op->opcode) &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* T = JMPZ_EX(X, L1), L1: JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
+ next = target_block->successors[1];
+ } else if (target->opcode == INV_EX_COND_EX(last_op->opcode) &&
+ target->result.var == last_op->result.var &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* T = JMPZ_EX(X, L1), L1: T = JMPNZ_EX({X|T}, L2) -> T = JMPZ_EX(X, L1+1) */
+ next = target_block->successors[1];
+ } else if (target->opcode == ZEND_BOOL &&
+ (SAME_VAR(target->op1, last_op->result) ||
+ SAME_VAR(target->op1, last_op->op1))) {
+ /* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
+ Z = JMPZ_EX(X,L1+1) */
+
+ /* NOTE: This optimization pattern is not safe, but works, */
+ /* because result of JMPZ_EX instruction */
+ /* is not used on the following path and */
+ /* should be used once on the branch path. */
+ /* */
+ /* The pattern works well only if jums processed in */
+ /* direct order, otherwise it breaks JMPZ_EX */
+ /* sequences too early. */
+ last_op->result.var = target->result.var;
+ next = target_block->successors[0];
+ } else {
+ break;
}
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ }
+
+ follow_block = get_follow_block(cfg, block, 1, opt_count);
+ if (target_block == follow_block) {
+ /* L: T = JMP[N]Z_EX(X, L+1) -> T = BOOL(X) */
+ last_op->opcode = ZEND_BOOL;
+ last_op->op2.num = 0;
+ block->successors_count = 1;
+ ++(*opt_count);
+ break;
}
break;
case ZEND_JMPZNZ: {
- int next = (block - blocks) + 1;
+optimize_jmpznz:
+ jmp_hitlist_count = 0;
+ target_block = get_target_block(cfg, block, 0, opt_count);
+ while (target_block->len == 1) {
+ target = op_array->opcodes + target_block->start;
- while (next < cfg->blocks_count && !(blocks[next].flags & ZEND_BB_REACHABLE)) {
- /* find first accessed one */
- next++;
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
+ next = target_block->successors[0];
+ } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ next = target_block->successors[0];
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ next = target_block->successors[1];
+ } else {
+ break;
+ }
+ CHECK_LOOP(next);
+ block->successors[0] = next;
+ ++(*opt_count);
+ target_block = get_target_block(cfg, block, 0, opt_count);
}
- if (last_op->op1_type == IS_CONST) {
- if (!zend_is_true(&ZEND_OP1_LITERAL(last_op))) {
- /* JMPZNZ(false,L1,L2) -> JMP(L1) */
- literal_dtor(&ZEND_OP1_LITERAL(last_op));
- last_op->opcode = ZEND_JMP;
- SET_UNUSED(last_op->op1);
- SET_UNUSED(last_op->op2);
- DEL_SOURCE(block, block->successors[1]);
- block->successors_count = 1;
+ jmp_hitlist_count = 0;
+ follow_block = get_target_block(cfg, block, 1, opt_count);
+ while (follow_block->len == 1) {
+ target = op_array->opcodes + follow_block->start;
+
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
+ next = follow_block->successors[0];
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ next = follow_block->successors[0];
+ } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
+ SAME_VAR(target->op1, last_op->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ next = target_block->successors[1];
} else {
- /* JMPZNZ(true,L1,L2) -> JMP(L2) */
- literal_dtor(&ZEND_OP1_LITERAL(last_op));
- last_op->opcode = ZEND_JMP;
- SET_UNUSED(last_op->op1);
- SET_UNUSED(last_op->op2);
- DEL_SOURCE(block, block->successors[0]);
- block->successors_count = 1;
- block->successors[0] = block->successors[1];
+ break;
}
+ CHECK_LOOP(next);
+ block->successors[1] = next;
++(*opt_count);
- } else if (block->successors[0] == block->successors[1]) {
- /* both goto the same one - it's JMP */
- if (!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
- /* JMPZNZ(?,L,L) -> JMP(L) */
- last_op->opcode = ZEND_JMP;
- SET_UNUSED(last_op->op1);
- SET_UNUSED(last_op->op2);
- block->successors_count = 1;
- ++(*opt_count);
- }
- } else if (block->successors[0] == next) {
+ follow_block = get_target_block(cfg, block, 1, opt_count);
+ }
+
+ next_block = get_next_block(cfg, block);
+ if (target_block == follow_block &&
+ !(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
+ /* JMPZNZ(?,L,L) -> JMP(L) */
+ last_op->opcode = ZEND_JMP;
+ SET_UNUSED(last_op->op1);
+ SET_UNUSED(last_op->op2);
+ last_op->extended_value = 0;
+ block->successors_count = 1;
+ ++(*opt_count);
+ } else if (target_block == next_block) {
/* jumping to next on Z - can follow to it and jump only on NZ */
/* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
+ int tmp = block->successors[0];
last_op->opcode = ZEND_JMPNZ;
block->successors[0] = block->successors[1];
- block->successors[1] = next;
+ block->successors[1] = tmp;
++(*opt_count);
- /* no need to add source */
- } else if (block->successors[1] == next) {
+ } else if (follow_block == next_block) {
/* jumping to next on NZ - can follow to it and jump only on Z */
/* JMPZNZ(X,L1,L2) L2: -> JMPZ(X,L1) */
last_op->opcode = ZEND_JMPZ;
++(*opt_count);
- /* no need to add source */
- }
-
- if (last_op->opcode == ZEND_JMPZNZ) {
- zend_uchar same_type = last_op->op1_type;
- zend_uchar same_var = VAR_NUM_EX(last_op->op1);
- zend_op *target;
- zend_op *target_end;
- zend_basic_block *target_block = blocks + block->successors[0];
-
-next_target_znz:
- target = op_array->opcodes + target_block->start;
- target_end = target + target_block->len;
- while (target < target_end && target->opcode == ZEND_NOP) {
- target++;
- }
- /* next block is only NOP's */
- if (target == target_end) {
- target_block = blocks + target_block->successors[0];
- ++(*opt_count);
- goto next_target_znz;
- } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMPNZ &&
- (target->op1_type & (IS_TMP_VAR|IS_CV)) &&
- same_type == target->op1_type &&
- same_var == VAR_NUM_EX(target->op1) &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[1];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- } else if (target->opcode == ZEND_JMP &&
- !(target_block->flags & ZEND_BB_PROTECTED)) {
- /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
- DEL_SOURCE(block, block->successors[0]);
- block->successors[0] = target_block->successors[0];
- ADD_SOURCE(block, block->successors[0]);
- ++(*opt_count);
- }
}
break;
}
@@ -1719,7 +1674,7 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use
while (opline >= end) {
/* usage checks */
- if (opline->result_type == IS_VAR) {
+ if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) {
switch (opline->opcode) {
case ZEND_ASSIGN_OP:
@@ -1736,17 +1691,12 @@ static void zend_t_usage(zend_cfg *cfg, zend_op_array *op_array, zend_bitset use
case ZEND_DO_FCALL_BY_NAME:
opline->result_type = IS_UNUSED;
break;
- }
- } else {
- zend_bitset_excl(usage, VAR_NUM(opline->result.var));
- }
- } else if (opline->result_type == IS_TMP_VAR) {
- if (!zend_bitset_in(usage, VAR_NUM(opline->result.var))) {
- switch (opline->opcode) {
case ZEND_POST_INC:
case ZEND_POST_DEC:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
+ case ZEND_POST_INC_STATIC_PROP:
+ case ZEND_POST_DEC_STATIC_PROP:
opline->opcode -= 2;
opline->result_type = IS_UNUSED;
break;
@@ -1884,8 +1834,8 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
zend_bitset usage;
void *checkpoint;
zend_op **Tsource;
- zend_uchar *same_t;
uint32_t opt_count;
+ int *jmp_hitlist;
/* Build CFG */
checkpoint = zend_arena_checkpoint(ctx->arena);
@@ -1905,8 +1855,8 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
bitset_len = zend_bitset_len(op_array->last_var + op_array->T);
Tsource = zend_arena_calloc(&ctx->arena, op_array->last_var + op_array->T, sizeof(zend_op *));
- same_t = zend_arena_alloc(&ctx->arena, op_array->last_var + op_array->T);
usage = zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
+ jmp_hitlist = zend_arena_alloc(&ctx->arena, cfg.blocks_count * sizeof(int));
blocks = cfg.blocks;
end = blocks + cfg.blocks_count;
@@ -1938,10 +1888,12 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
}
+ opt_count = 0;
+
/* Jump optimization for each block */
for (b = blocks; b < end; b++) {
if (b->flags & ZEND_BB_REACHABLE) {
- zend_jmp_optimization(b, op_array, &cfg, same_t, &opt_count);
+ zend_jmp_optimization(b, op_array, &cfg, jmp_hitlist, &opt_count);
}
}
@@ -1956,8 +1908,6 @@ void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
}
- zend_bitset_clear(usage, bitset_len);
- zend_t_usage(&cfg, op_array, usage, ctx);
assemble_code_blocks(&cfg, op_array, ctx);
if (ctx->debug_level & ZEND_DUMP_AFTER_BLOCK_PASS) {
diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c
index f754dbaa44..4aabe04c6e 100644
--- a/ext/opcache/Optimizer/compact_literals.c
+++ b/ext/opcache/Optimizer/compact_literals.c
@@ -56,25 +56,31 @@ typedef struct _literal_info {
info[n].flags = ((kind) | (related)); \
} while (0)
-static zend_bool class_name_type_hint(const zend_op_array *op_array, uint32_t arg_num)
+static size_t type_num_classes(const zend_op_array *op_array, uint32_t arg_num)
{
zend_arg_info *arg_info;
-
if (arg_num > 0) {
- if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
- if (EXPECTED(arg_num <= op_array->num_args)) {
- arg_info = &op_array->arg_info[arg_num-1];
- } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
- arg_info = &op_array->arg_info[op_array->num_args];
- } else {
- return 0;
- }
- return ZEND_TYPE_IS_CLASS(arg_info->type);
+ if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
+ return 0;
+ }
+ if (EXPECTED(arg_num <= op_array->num_args)) {
+ arg_info = &op_array->arg_info[arg_num-1];
+ } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
+ arg_info = &op_array->arg_info[op_array->num_args];
+ } else {
+ return 0;
}
} else {
arg_info = op_array->arg_info - 1;
- return ZEND_TYPE_IS_CLASS(arg_info->type);
}
+
+ if (ZEND_TYPE_HAS_CLASS(arg_info->type)) {
+ if (ZEND_TYPE_HAS_LIST(arg_info->type)) {
+ return ZEND_TYPE_LIST(arg_info->type)->num_types;
+ }
+ return 1;
+ }
+
return 0;
}
@@ -168,13 +174,13 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2);
break;
case ZEND_DEFINED:
- LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 2);
+ LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1);
break;
case ZEND_FETCH_CONSTANT:
- if ((opline->op1.num & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
- LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 5);
- } else {
+ if (opline->op1.num & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 3);
+ } else {
+ LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 2);
}
break;
case ZEND_FETCH_CLASS_CONSTANT:
@@ -503,24 +509,25 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
}
switch (opline->opcode) {
case ZEND_RECV_INIT:
- if (class_name_type_hint(op_array, opline->op1.num)) {
- opline->extended_value = cache_size;
- cache_size += sizeof(void *);
- }
- break;
case ZEND_RECV:
case ZEND_RECV_VARIADIC:
- if (class_name_type_hint(op_array, opline->op1.num)) {
- opline->op2.num = cache_size;
- cache_size += sizeof(void *);
+ {
+ size_t num_classes = type_num_classes(op_array, opline->op1.num);
+ if (num_classes) {
+ opline->extended_value = cache_size;
+ cache_size += num_classes * sizeof(void *);
}
break;
+ }
case ZEND_VERIFY_RETURN_TYPE:
- if (class_name_type_hint(op_array, 0)) {
+ {
+ size_t num_classes = type_num_classes(op_array, 0);
+ if (num_classes) {
opline->op2.num = cache_size;
- cache_size += sizeof(void *);
+ cache_size += num_classes * sizeof(void *);
}
break;
+ }
case ZEND_ASSIGN_STATIC_PROP_OP:
if (opline->op1_type == IS_CONST) {
// op1 static property
diff --git a/ext/opcache/Optimizer/dce.c b/ext/opcache/Optimizer/dce.c
index 8370bdc779..ea81687bf4 100644
--- a/ext/opcache/Optimizer/dce.c
+++ b/ext/opcache/Optimizer/dce.c
@@ -124,6 +124,7 @@ static inline zend_bool may_have_side_effects(
case ZEND_IN_ARRAY:
case ZEND_FUNC_NUM_ARGS:
case ZEND_FUNC_GET_ARGS:
+ case ZEND_ARRAY_KEY_EXISTS:
/* No side effects */
return 0;
case ZEND_ROPE_END:
@@ -241,6 +242,8 @@ static inline zend_bool may_have_side_effects(
}
}
return 0;
+ case ZEND_CHECK_VAR:
+ return (OP1_INFO() & MAY_BE_UNDEF) != 0;
default:
/* For everything we didn't handle, assume a side-effect */
return 1;
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index 471328b6c5..8802577154 100644
--- a/ext/opcache/Optimizer/dfa_pass.c
+++ b/ext/opcache/Optimizer/dfa_pass.c
@@ -125,33 +125,6 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
return SUCCESS;
}
-static zend_bool is_smart_branch_inhibiting_nop(
- zend_op_array *op_array, uint32_t target, uint32_t current,
- zend_basic_block *b, zend_basic_block *blocks_end)
-{
- uint32_t next;
- /* Target points one past the last non-nop instruction. Make sure there is one. */
- if (target == 0) {
- return 0;
- }
-
- /* Find the next instruction, skipping unreachable or empty blocks. */
- next = current + 1;
- if (next >= b->start + b->len) {
- do {
- b++;
- if (b == blocks_end) {
- return 0;
- }
- } while (!(b->flags & ZEND_BB_REACHABLE) || b->len == 0);
- next = b->start;
- }
-
- return (op_array->opcodes[next].opcode == ZEND_JMPZ ||
- op_array->opcodes[next].opcode == ZEND_JMPNZ) &&
- zend_is_smart_branch(op_array->opcodes + target - 1);
-}
-
static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_optimizer_ctx *ctx)
{
zend_basic_block *blocks = ssa->cfg.blocks;
@@ -199,8 +172,7 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
old_end = b->start + b->len;
while (i < old_end) {
shiftlist[i] = i - target;
- if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP) ||
- is_smart_branch_inhibiting_nop(op_array, target, i, b, blocks_end)) {
+ if (EXPECTED(op_array->opcodes[i].opcode != ZEND_NOP)) {
if (i != target) {
op_array->opcodes[target] = op_array->opcodes[i];
ssa->ops[target] = ssa->ops[i];
@@ -323,6 +295,8 @@ static inline zend_bool can_elide_return_type_check(
zend_ssa_var_info *use_info = &ssa->var_info[ssa_op->op1_use];
zend_ssa_var_info *def_info = &ssa->var_info[ssa_op->op1_def];
+ /* TODO: It would be better to rewrite this without using def_info,
+ * which may not be an exact representation of the type. */
if (use_info->type & MAY_BE_REF) {
return 0;
}
@@ -333,11 +307,11 @@ static inline zend_bool can_elide_return_type_check(
}
/* These types are not represented exactly */
- if (ZEND_TYPE_CODE(info->type) == IS_CALLABLE || ZEND_TYPE_CODE(info->type) == IS_ITERABLE) {
+ if (ZEND_TYPE_FULL_MASK(info->type) & (MAY_BE_CALLABLE|MAY_BE_ITERABLE)) {
return 0;
}
- if (ZEND_TYPE_IS_CLASS(info->type)) {
+ if (ZEND_TYPE_HAS_CLASS(info->type)) {
if (!use_info->ce || !def_info->ce || !safe_instanceof(use_info->ce, def_info->ce)) {
return 0;
}
@@ -492,6 +466,24 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
MAKE_NOP(send_array);
removed_ops++;
+ op_num = call_info->caller_call_opline - op_array->opcodes;
+ ssa_op = ssa->ops + op_num;
+ if (ssa_op->result_def >= 0) {
+ int var = ssa_op->result_def;
+ int use = ssa->vars[var].use_chain;
+
+ if (ssa->vars[var].phi_use_chain == NULL) {
+ if (ssa->ops[use].op1_use == var
+ && ssa->ops[use].op1_use_chain == -1) {
+ call_info->caller_call_opline->result_type = IS_TMP_VAR;
+ op_array->opcodes[use].op1_type = IS_TMP_VAR;
+ } else if (ssa->ops[use].op2_use == var
+ && ssa->ops[use].op2_use_chain == -1) {
+ call_info->caller_call_opline->result_type = IS_TMP_VAR;
+ op_array->opcodes[use].op2_type = IS_TMP_VAR;
+ }
+ }
+ }
}
}
}
@@ -541,8 +533,7 @@ static void compress_block(zend_op_array *op_array, zend_basic_block *block)
while (block->len > 0) {
zend_op *opline = &op_array->opcodes[block->start + block->len - 1];
- if (opline->opcode == ZEND_NOP
- && (block->len == 1 || !zend_is_smart_branch(opline - 1))) {
+ if (opline->opcode == ZEND_NOP) {
block->len--;
} else {
break;
@@ -1204,8 +1195,64 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx
/* Update opcodes */
op_array->opcodes[op_2].result_type = opline->op1_type;
op_array->opcodes[op_2].result.var = opline->op1.var;
+
MAKE_NOP(opline);
remove_nops = 1;
+
+ if (op_array->opcodes[op_2].opcode == ZEND_SUB
+ && op_array->opcodes[op_2].op1_type == op_array->opcodes[op_2].result_type
+ && op_array->opcodes[op_2].op1.var == op_array->opcodes[op_2].result.var
+ && op_array->opcodes[op_2].op2_type == IS_CONST
+ && Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == IS_LONG
+ && Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == 1
+ && ssa->ops[op_2].op1_use >= 0
+ && !(ssa->var_info[ssa->ops[op_2].op1_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+
+ op_array->opcodes[op_2].opcode = ZEND_PRE_DEC;
+ SET_UNUSED(op_array->opcodes[op_2].op2);
+ SET_UNUSED(op_array->opcodes[op_2].result);
+
+ ssa->ops[op_2].result_def = -1;
+ ssa->ops[op_2].op1_def = v;
+
+ } else if (op_array->opcodes[op_2].opcode == ZEND_ADD
+ && op_array->opcodes[op_2].op1_type == op_array->opcodes[op_2].result_type
+ && op_array->opcodes[op_2].op1.var == op_array->opcodes[op_2].result.var
+ && op_array->opcodes[op_2].op2_type == IS_CONST
+ && Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == IS_LONG
+ && Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op2.constant)) == 1
+ && ssa->ops[op_2].op1_use >= 0
+ && !(ssa->var_info[ssa->ops[op_2].op1_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+
+ op_array->opcodes[op_2].opcode = ZEND_PRE_INC;
+ SET_UNUSED(op_array->opcodes[op_2].op2);
+ SET_UNUSED(op_array->opcodes[op_2].result);
+
+ ssa->ops[op_2].result_def = -1;
+ ssa->ops[op_2].op1_def = v;
+
+ } else if (op_array->opcodes[op_2].opcode == ZEND_ADD
+ && op_array->opcodes[op_2].op2_type == op_array->opcodes[op_2].result_type
+ && op_array->opcodes[op_2].op2.var == op_array->opcodes[op_2].result.var
+ && op_array->opcodes[op_2].op1_type == IS_CONST
+ && Z_TYPE_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op1.constant)) == IS_LONG
+ && Z_LVAL_P(CT_CONSTANT_EX(op_array, op_array->opcodes[op_2].op1.constant)) == 1
+ && ssa->ops[op_2].op2_use >= 0
+ && !(ssa->var_info[ssa->ops[op_2].op2_use].type & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+
+ op_array->opcodes[op_2].opcode = ZEND_PRE_INC;
+ op_array->opcodes[op_2].op1_type = op_array->opcodes[op_2].op2_type;
+ op_array->opcodes[op_2].op1.var = op_array->opcodes[op_2].op2.var;
+ SET_UNUSED(op_array->opcodes[op_2].op2);
+ SET_UNUSED(op_array->opcodes[op_2].result);
+
+ ssa->ops[op_2].result_def = -1;
+ ssa->ops[op_2].op1_def = v;
+ ssa->ops[op_2].op1_use = ssa->ops[op_2].op2_use;
+ ssa->ops[op_2].op1_use_chain = ssa->ops[op_2].op2_use_chain;
+ ssa->ops[op_2].op2_use = -1;
+ ssa->ops[op_2].op2_use_chain = -1;
+ }
}
} else if (opline->op2_type == IS_CONST
|| ((opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV))
diff --git a/ext/opcache/Optimizer/escape_analysis.c b/ext/opcache/Optimizer/escape_analysis.c
index c561bec9dc..3b8733eaae 100644
--- a/ext/opcache/Optimizer/escape_analysis.c
+++ b/ext/opcache/Optimizer/escape_analysis.c
@@ -176,12 +176,12 @@ static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, in
case ZEND_NEW:
/* objects with destructors should escape */
if (opline->op1_type == IS_CONST) {
- zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)+1));
- uint32_t forbidden_flags = ZEND_ACC_INHERITED
+ zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1));
+ uint32_t forbidden_flags =
/* These flags will always cause an exception */
- | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
+ ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
| ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT;
- if (ce && !ce->create_object && !ce->constructor &&
+ if (ce && !ce->parent && !ce->create_object && !ce->constructor &&
!ce->destructor && !ce->__get && !ce->__set &&
!(ce->ce_flags & forbidden_flags) &&
(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
@@ -191,7 +191,7 @@ static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, in
break;
case ZEND_QM_ASSIGN:
if (opline->op1_type == IS_CONST
- && Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)) == IS_ARRAY) {
+ && Z_TYPE_P(CRT_CONSTANT(opline->op1)) == IS_ARRAY) {
return 1;
}
if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_ARRAY)) {
@@ -208,7 +208,7 @@ static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, in
switch (opline->opcode) {
case ZEND_ASSIGN:
if (opline->op2_type == IS_CONST
- && Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_ARRAY) {
+ && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_ARRAY) {
return 1;
}
if (opline->op2_type == IS_CV && (OP2_INFO() & MAY_BE_ARRAY)) {
@@ -245,10 +245,9 @@ static int is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int var
case ZEND_NEW:
/* objects with destructors should escape */
if (opline->op1_type == IS_CONST) {
- zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)+1));
+ zend_class_entry *ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1));
if (ce && !ce->create_object && !ce->constructor &&
- !ce->destructor && !ce->__get && !ce->__set &&
- !(ce->ce_flags & ZEND_ACC_INHERITED)) {
+ !ce->destructor && !ce->__get && !ce->__set && !ce->parent) {
return 1;
}
}
@@ -338,7 +337,7 @@ static int is_escape_use(zend_op_array *op_array, zend_ssa *ssa, int use, int va
if (opline->op1_type != IS_CV
|| (OP1_INFO() & MAY_BE_REF)
|| (op->op1_def >= 0 && ssa->vars[op->op1_def].alias)) {
- /* asignment into escaping structure */
+ /* assignment into escaping structure */
return 1;
}
/* reference dependencies processed separately */
@@ -354,7 +353,7 @@ static int is_escape_use(zend_op_array *op_array, zend_ssa *ssa, int use, int va
if (opline->op1_type != IS_CV
|| (OP1_INFO() & MAY_BE_REF)
|| (op->op1_def >= 0 && ssa->vars[op->op1_def].alias)) {
- /* asignment into escaping variable */
+ /* assignment into escaping variable */
return 1;
}
if (opline->op2_type == IS_CV || opline->result_type != IS_UNUSED) {
diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c
index ae707a2409..2894ca89f4 100644
--- a/ext/opcache/Optimizer/optimize_func_calls.c
+++ b/ext/opcache/Optimizer/optimize_func_calls.c
@@ -116,7 +116,7 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
for (i = 0; i < num_args; i++) {
/* Don't inline functions with by-reference arguments. This would require
* correct handling of INDIRECT arguments. */
- if (func->op_array.arg_info[i].pass_by_reference) {
+ if (ZEND_ARG_SEND_MODE(&func->op_array.arg_info[i])) {
return;
}
}
@@ -126,7 +126,7 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
i = fcall->extended_value;
do {
- if (Z_TYPE_P(RT_CONSTANT(&func->op_array.opcodes[i], func->op_array.opcodes[i].op2)) == IS_CONSTANT_AST) {
+ if (Z_TYPE_P(CRT_CONSTANT_EX(&func->op_array, &func->op_array.opcodes[i], func->op_array.opcodes[i].op2)) == IS_CONSTANT_AST) {
return;
}
i++;
@@ -136,7 +136,7 @@ static void zend_try_inline_call(zend_op_array *op_array, zend_op *fcall, zend_o
if (RETURN_VALUE_USED(opline)) {
zval zv;
- ZVAL_COPY(&zv, RT_CONSTANT(ret_opline, ret_opline->op1));
+ ZVAL_COPY(&zv, CRT_CONSTANT_EX(&func->op_array, ret_opline, ret_opline->op1));
opline->opcode = ZEND_QM_ASSIGN;
opline->op1_type = IS_CONST;
opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
@@ -173,7 +173,7 @@ void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_INIT_FCALL:
case ZEND_NEW:
call_stack[call].func = zend_optimizer_get_called_func(
- ctx->script, op_array, opline, 0);
+ ctx->script, op_array, opline);
call_stack[call].try_inline = opline->opcode != ZEND_NEW;
/* break missing intentionally */
case ZEND_INIT_DYNAMIC_CALL:
diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c
index 825091bfc3..6f7400159d 100644
--- a/ext/opcache/Optimizer/optimize_temp_vars_5.c
+++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c
@@ -102,7 +102,7 @@ void zend_optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_c
if (!zend_bitset_in(valid_T, currT)) {
int use_new_var = 0;
- /* Code in "finally" blocks may modify temorary variables.
+ /* Code in "finally" blocks may modify temporary variables.
* We allocate new temporaries for values that need to
* relive FAST_CALLs.
*/
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1.c
index 8f41730114..7d244a283c 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1.c
@@ -19,10 +19,11 @@
+----------------------------------------------------------------------+
*/
-/* pass 1
- * - substitute persistent constants (true, false, null, etc)
- * - perform compile-time evaluation of constant binary and unary operations
- * - convert CAST(IS_BOOL,x) into BOOL(x)
+/* pass 1 (Simple local optimizations)
+ * - persistent constant substitution (true, false, null, etc)
+ * - constant casting (ADD expects numbers, CONCAT strings, etc)
+ * - constant expression evaluation
+ * - optimize constant conditional JMPs
* - pre-evaluate constant function calls
* - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM
*/
@@ -37,7 +38,6 @@
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
- int i = 0;
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
zend_bool collect_constants = (ZEND_OPTIMIZER_PASS_15 & ctx->optimization_level)?
@@ -49,21 +49,80 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_SUB:
case ZEND_MUL:
case ZEND_DIV:
- case ZEND_MOD:
case ZEND_POW:
+ if (opline->op1_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0)) {
+ convert_scalar_to_number(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ }
+ if (opline->op2_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
+ convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ if (opline->op1_type == IS_CONST) {
+ goto constant_binary_op;
+ }
+ }
+ break;
+
+ case ZEND_MOD:
case ZEND_SL:
case ZEND_SR:
+ if (opline->op1_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_LONG) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (!(Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING
+ && !is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0))) {
+ convert_to_long(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ }
+ if (opline->op2_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
+ && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
+ convert_to_long(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ if (opline->op1_type == IS_CONST) {
+ goto constant_binary_op;
+ }
+ }
+ break;
+
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
+ if (opline->op1_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP1_LITERAL(opline));
+ }
+ }
+ if (opline->op2_type == IS_CONST) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP2_LITERAL(opline));
+ }
+ if (opline->op1_type == IS_CONST) {
+ goto constant_binary_op;
+ }
+ }
+ break;
+
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
- case ZEND_BW_OR:
- case ZEND_BW_AND:
- case ZEND_BW_XOR:
case ZEND_BOOL_XOR:
case ZEND_SPACESHIP:
case ZEND_CASE:
@@ -72,6 +131,7 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
/* binary operation with constant operands */
zval result;
+constant_binary_op:
if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) {
literal_dtor(&ZEND_OP1_LITERAL(opline));
literal_dtor(&ZEND_OP2_LITERAL(opline));
@@ -86,6 +146,37 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
}
break;
+ case ZEND_ASSIGN_OP:
+ if (opline->op2_type == IS_CONST) {
+ if (opline->extended_value == ZEND_ADD
+ || opline->extended_value == ZEND_SUB
+ || opline->extended_value == ZEND_MUL
+ || opline->extended_value == ZEND_DIV
+ || opline->extended_value == ZEND_POW) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
+ convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ } else if (opline->extended_value == ZEND_MOD
+ || opline->extended_value == ZEND_SL
+ || opline->extended_value == ZEND_SR) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
+ /* don't optimise if it should produce a runtime numeric string error */
+ if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
+ && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
+ convert_to_long(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ } else if (opline->extended_value == ZEND_CONCAT) {
+ if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
+ convert_to_string(&ZEND_OP2_LITERAL(opline));
+ }
+ }
+ }
+ break;
+
case ZEND_CAST:
if (opline->op1_type == IS_CONST) {
/* cast of constant operand */
@@ -103,12 +194,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
}
-
- if (opline->extended_value == _IS_BOOL) {
- /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
- opline->opcode = ZEND_BOOL;
- opline->extended_value = 0;
- }
break;
case ZEND_BW_NOT:
@@ -562,6 +647,71 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
#endif
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
+ in case we know it wouldn't jump */
+ if (opline->op1_type == IS_CONST) {
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
+ if (opline->opcode == ZEND_JMPZ_EX) {
+ opline->opcode = ZEND_QM_ASSIGN;
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_TRUE(&ZEND_OP1_LITERAL(opline));
+ opline->op2.num = 0;
+ break;
+ }
+ } else {
+ if (opline->opcode == ZEND_JMPNZ_EX) {
+ opline->opcode = ZEND_QM_ASSIGN;
+ zval_ptr_dtor_nogc(&ZEND_OP1_LITERAL(opline));
+ ZVAL_FALSE(&ZEND_OP1_LITERAL(opline));
+ opline->op2.num = 0;
+ break;
+ }
+ }
+ }
+ collect_constants = 0;
+ break;
+
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ if (opline->op1_type == IS_CONST) {
+ int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
+
+ if (opline->opcode == ZEND_JMPZ) {
+ should_jmp = !should_jmp;
+ }
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ opline->op1_type = IS_UNUSED;
+ if (should_jmp) {
+ opline->opcode = ZEND_JMP;
+ COPY_NODE(opline->op1, opline->op2);
+ opline->op2.num = 0;
+ } else {
+ MAKE_NOP(opline);
+ break;
+ }
+ }
+ collect_constants = 0;
+ break;
+
+ case ZEND_JMPZNZ:
+ if (opline->op1_type == IS_CONST) {
+ zend_op *target_opline;
+
+ if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
+ target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
+ } else {
+ target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
+ }
+ literal_dtor(&ZEND_OP1_LITERAL(opline));
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
+ opline->op1_type = IS_UNUSED;
+ opline->opcode = ZEND_JMP;
+ }
+ collect_constants = 0;
+ break;
+
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
@@ -571,11 +721,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_FAST_CALL:
case ZEND_FAST_RET:
case ZEND_JMP:
- case ZEND_JMPZNZ:
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
case ZEND_FE_RESET_R:
case ZEND_FE_RESET_RW:
case ZEND_FE_FETCH_R:
@@ -587,6 +732,5 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
break;
}
opline++;
- i++;
}
}
diff --git a/ext/opcache/Optimizer/pass2.c b/ext/opcache/Optimizer/pass2.c
deleted file mode 100644
index 01e118e7e3..0000000000
--- a/ext/opcache/Optimizer/pass2.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | Zend OPcache |
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | http://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Andi Gutmans <andi@php.net> |
- | Zeev Suraski <zeev@php.net> |
- | Stanislav Malyshev <stas@zend.com> |
- | Dmitry Stogov <dmitry@php.net> |
- +----------------------------------------------------------------------+
-*/
-
-/* pass 2:
- * - convert non-numeric constants to numeric constants in numeric operators
- * - optimize constant conditional JMPs
- */
-
-#include "php.h"
-#include "Optimizer/zend_optimizer.h"
-#include "Optimizer/zend_optimizer_internal.h"
-#include "zend_API.h"
-#include "zend_constants.h"
-#include "zend_execute.h"
-#include "zend_vm.h"
-
-void zend_optimizer_pass2(zend_op_array *op_array)
-{
- zend_op *opline;
- zend_op *end = op_array->opcodes + op_array->last;
-
- opline = op_array->opcodes;
- while (opline < end) {
- switch (opline->opcode) {
- case ZEND_ADD:
- case ZEND_SUB:
- case ZEND_MUL:
- case ZEND_DIV:
- case ZEND_POW:
- if (opline->op1_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0)) {
- convert_scalar_to_number(&ZEND_OP1_LITERAL(opline));
- }
- }
- }
- if (opline->op2_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
- convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
- }
- }
- }
- break;
-
- case ZEND_MOD:
- case ZEND_SL:
- case ZEND_SR:
- if (opline->op1_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_LONG) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (!(Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING
- && !is_numeric_string(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), NULL, NULL, 0))) {
- convert_to_long(&ZEND_OP1_LITERAL(opline));
- }
- }
- }
- if (opline->op2_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
- && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
- convert_to_long(&ZEND_OP2_LITERAL(opline));
- }
- }
- }
- break;
-
- case ZEND_CONCAT:
- case ZEND_FAST_CONCAT:
- if (opline->op1_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP1_LITERAL(opline));
- }
- }
- if (opline->op2_type == IS_CONST) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP2_LITERAL(opline));
- }
- }
- break;
-
- case ZEND_ASSIGN_OP:
- if (opline->op2_type == IS_CONST) {
- if (opline->extended_value == ZEND_ADD
- || opline->extended_value == ZEND_SUB
- || opline->extended_value == ZEND_MUL
- || opline->extended_value == ZEND_DIV
- || opline->extended_value == ZEND_POW) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) {
- convert_scalar_to_number(&ZEND_OP2_LITERAL(opline));
- }
- }
- } else if (opline->extended_value == ZEND_MOD
- || opline->extended_value == ZEND_SL
- || opline->extended_value == ZEND_SR) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
- /* don't optimise if it should produce a runtime numeric string error */
- if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
- && !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
- convert_to_long(&ZEND_OP2_LITERAL(opline));
- }
- }
- } else if (opline->extended_value == ZEND_CONCAT) {
- if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {
- convert_to_string(&ZEND_OP2_LITERAL(opline));
- }
- }
- }
- break;
-
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- /* convert Ti = JMPZ_EX(Ti, L) to JMPZ(Ti, L) */
-#if 0
- /* Disabled unsafe pattern: in conjunction with
- * ZEND_VM_SMART_BRANCH() this may improperly eliminate
- * assignment to Ti.
- */
- if (opline->op1_type == IS_TMP_VAR &&
- opline->result_type == IS_TMP_VAR &&
- opline->op1.var == opline->result.var) {
- opline->opcode -= 3;
- SET_UNUSED(opline->result);
- } else
-#endif
- /* convert Ti = JMPZ_EX(C, L) => Ti = QM_ASSIGN(C)
- in case we know it wouldn't jump */
- if (opline->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
- if (opline->opcode == ZEND_JMPZ_EX) {
- should_jmp = !should_jmp;
- }
- if (!should_jmp) {
- opline->opcode = ZEND_QM_ASSIGN;
- SET_UNUSED(opline->op2);
- }
- }
- break;
-
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- if (opline->op1_type == IS_CONST) {
- int should_jmp = zend_is_true(&ZEND_OP1_LITERAL(opline));
-
- if (opline->opcode == ZEND_JMPZ) {
- should_jmp = !should_jmp;
- }
- literal_dtor(&ZEND_OP1_LITERAL(opline));
- opline->op1_type = IS_UNUSED;
- if (should_jmp) {
- opline->opcode = ZEND_JMP;
- COPY_NODE(opline->op1, opline->op2);
- } else {
- MAKE_NOP(opline);
- }
- break;
- }
- if ((opline + 1)->opcode == ZEND_JMP) {
- /* JMPZ(X, L1), JMP(L2) => JMPZNZ(X, L1, L2) */
- /* JMPNZ(X, L1), JMP(L2) => JMPZNZ(X, L2, L1) */
- if (ZEND_OP2_JMP_ADDR(opline) == ZEND_OP1_JMP_ADDR(opline + 1)) {
- /* JMPZ(X, L1), JMP(L1) => NOP, JMP(L1) */
- if (opline->op1_type == IS_CV) {
- opline->opcode = ZEND_CHECK_VAR;
- opline->op2.num = 0;
- } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
- opline->opcode = ZEND_FREE;
- opline->op2.num = 0;
- } else {
- MAKE_NOP(opline);
- }
- } else {
- if (opline->opcode == ZEND_JMPZ) {
- opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP1_JMP_ADDR(opline + 1));
- } else {
- opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP2_JMP_ADDR(opline));
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(opline + 1));
- }
- opline->opcode = ZEND_JMPZNZ;
- }
- }
- break;
-
- case ZEND_JMPZNZ:
- if (opline->op1_type == IS_CONST) {
- zend_op *target_opline;
-
- if (zend_is_true(&ZEND_OP1_LITERAL(opline))) {
- target_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); /* JMPNZ */
- } else {
- target_opline = ZEND_OP2_JMP_ADDR(opline); /* JMPZ */
- }
- literal_dtor(&ZEND_OP1_LITERAL(opline));
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target_opline);
- opline->op1_type = IS_UNUSED;
- opline->opcode = ZEND_JMP;
- }
- break;
- }
- opline++;
- }
-}
diff --git a/ext/opcache/Optimizer/pass3.c b/ext/opcache/Optimizer/pass3.c
index 5bbb2b0854..f98c41848c 100644
--- a/ext/opcache/Optimizer/pass3.c
+++ b/ext/opcache/Optimizer/pass3.c
@@ -19,10 +19,8 @@
+----------------------------------------------------------------------+
*/
-/* pass 3:
- * - optimize $i = $i+expr to $i+=expr
+/* pass 3: (Jump optimization)
* - optimize series of JMPs
- * - change $i++ to ++$i where possible
*/
#include "php.h"
@@ -34,388 +32,325 @@
#include "zend_vm.h"
/* we use "jmp_hitlist" to avoid infinity loops during jmp optimization */
-#define CHECK_JMP(target, label) \
- for (i=0; i<jmp_hitlist_count; i++) { \
- if (jmp_hitlist[i] == ZEND_OP1_JMP_ADDR(target)) { \
- goto label; \
- } \
- } \
- jmp_hitlist[jmp_hitlist_count++] = ZEND_OP1_JMP_ADDR(target);
+static zend_always_inline int in_hitlist(zend_op *target, zend_op **jmp_hitlist, int jmp_hitlist_count)
+{
+ int i;
-#define CHECK_JMP2(target, label) \
- for (i=0; i<jmp_hitlist_count; i++) { \
- if (jmp_hitlist[i] == ZEND_OP2_JMP_ADDR(target)) { \
- goto label; \
- } \
- } \
- jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2_JMP_ADDR(target);
+ for (i = 0; i < jmp_hitlist_count; i++) {
+ if (jmp_hitlist[i] == target) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define CHECK_LOOP(target) \
+ if (EXPECTED(!in_hitlist(target, jmp_hitlist, jmp_hitlist_count))) { \
+ jmp_hitlist[jmp_hitlist_count++] = target; \
+ } else { \
+ break; \
+ }
void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx)
{
zend_op *opline;
- zend_op *end = op_array->opcodes + op_array->last;
+ zend_op *end;
+ zend_op *target;
zend_op **jmp_hitlist;
int jmp_hitlist_count;
- int i;
- uint32_t opline_num = 0;
ALLOCA_FLAG(use_heap);
jmp_hitlist = (zend_op**)do_alloca(sizeof(zend_op*)*op_array->last, use_heap);
opline = op_array->opcodes;
+ end = opline + op_array->last;
while (opline < end) {
- jmp_hitlist_count = 0;
switch (opline->opcode) {
- case ZEND_ADD:
- case ZEND_SUB:
- case ZEND_MUL:
- case ZEND_DIV:
- case ZEND_MOD:
- case ZEND_POW:
- case ZEND_CONCAT:
- case ZEND_SL:
- case ZEND_SR:
- case ZEND_BW_OR:
- case ZEND_BW_AND:
- case ZEND_BW_XOR:
- {
- zend_op *next_opline = opline + 1;
-
- while (next_opline < end && next_opline->opcode == ZEND_NOP) {
- ++next_opline;
- }
+ case ZEND_JMP:
+ jmp_hitlist_count = 0;
- if (next_opline >= end || next_opline->opcode != ZEND_ASSIGN) {
+ target = ZEND_OP1_JMP_ADDR(opline);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
break;
}
-
- /* change $i=expr+$i to $i=$i+expr so that the following optimization
- * works on it. Only do this if we are ignoring operator overloading,
- * as operand order might be significant otherwise. */
- if ((ctx->optimization_level & ZEND_OPTIMIZER_IGNORE_OVERLOADING)
- && (opline->op2_type & (IS_VAR | IS_CV))
- && opline->op2.var == next_opline->op1.var &&
- (opline->opcode == ZEND_ADD ||
- opline->opcode == ZEND_MUL ||
- opline->opcode == ZEND_BW_OR ||
- opline->opcode == ZEND_BW_AND ||
- opline->opcode == ZEND_BW_XOR)) {
- zend_uchar tmp_type = opline->op1_type;
- znode_op tmp = opline->op1;
-
- if (opline->opcode != ZEND_ADD
- || (opline->op1_type == IS_CONST
- && Z_TYPE(ZEND_OP1_LITERAL(opline)) != IS_ARRAY)) {
- /* protection from array add: $a = array + $a is not commutative! */
- COPY_NODE(opline->op1, opline->op2);
- COPY_NODE(opline->op2, tmp);
- }
- }
-
- if (ZEND_IS_BINARY_ASSIGN_OP_OPCODE(opline->opcode)
- && (opline->op1_type & (IS_VAR | IS_CV))
- && opline->op1.var == next_opline->op1.var
- && opline->op1_type == next_opline->op1_type) {
- opline->extended_value = opline->opcode;
- opline->opcode = ZEND_ASSIGN_OP;
- COPY_NODE(opline->result, next_opline->result);
- MAKE_NOP(next_opline);
- opline++;
- opline_num++;
- }
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target);
}
- break;
- case ZEND_JMP:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
-
- /* convert L: JMP L+1 to NOP */
- if (ZEND_OP1_JMP_ADDR(opline) == opline + 1) {
+ if (target == opline + 1) {
+ /* convert L: JMP L+1 to NOP */
MAKE_NOP(opline);
- goto done_jmp_optimization;
- }
-
- /* convert JMP L1 ... L1: JMP L2 to JMP L2 .. L1: JMP L2 */
- while (ZEND_OP1_JMP_ADDR(opline) < end
- && ZEND_OP1_JMP_ADDR(opline)->opcode == ZEND_JMP) {
- zend_op *target = ZEND_OP1_JMP_ADDR(opline);
- CHECK_JMP(target, done_jmp_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op1, ZEND_OP1_JMP_ADDR(target));
+ } else if (target->opcode == ZEND_JMPZNZ) {
+ /* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ L1,L2 */
+ *opline = *target;
+ if (opline->op1_type == IS_CONST) {
+ zval zv;
+ ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(opline));
+ opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
+ }
+ goto optimize_jmpznz;
+ } else if ((target->opcode == ZEND_RETURN ||
+ target->opcode == ZEND_RETURN_BY_REF ||
+ target->opcode == ZEND_GENERATOR_RETURN ||
+ target->opcode == ZEND_EXIT) &&
+ !(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
+ /* JMP L, L: RETURN to immediate RETURN */
+ *opline = *target;
+ if (opline->op1_type == IS_CONST) {
+ zval zv;
+ ZVAL_COPY(&zv, &ZEND_OP1_LITERAL(opline));
+ opline->op1.constant = zend_optimizer_add_literal(op_array, &zv);
+ }
+ } else if (opline > op_array->opcodes &&
+ ((opline-1)->opcode == ZEND_JMPZ ||
+ (opline-1)->opcode == ZEND_JMPNZ)) {
+ if (ZEND_OP2_JMP_ADDR(opline-1) == target) {
+ /* JMPZ(X,L1), JMP(L1) -> NOP, JMP(L1) */
+ if ((opline-1)->op1_type == IS_CV) {
+ (opline-1)->opcode = ZEND_CHECK_VAR;
+ (opline-1)->op2.num = 0;
+ } else if ((opline-1)->op1_type & (IS_TMP_VAR|IS_VAR)) {
+ (opline-1)->opcode = ZEND_FREE;
+ (opline-1)->op2.num = 0;
+ } else {
+ MAKE_NOP(opline-1);
+ }
+ } else {
+ /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
+ if ((opline-1)->opcode == ZEND_JMPZ) {
+ (opline-1)->extended_value = ZEND_OPLINE_TO_OFFSET((opline-1), target);
+ } else {
+ (opline-1)->extended_value = ZEND_OPLINE_TO_OFFSET((opline-1), ZEND_OP2_JMP_ADDR(opline-1));
+ ZEND_SET_OP_JMP_ADDR((opline-1), (opline-1)->op2, target);
+ }
+ (opline-1)->opcode = ZEND_JMPZNZ;
+ }
}
break;
case ZEND_JMP_SET:
case ZEND_COALESCE:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
+ jmp_hitlist_count = 0;
- while (ZEND_OP2_JMP_ADDR(opline) < end) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
if (target->opcode == ZEND_JMP) {
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
} else {
break;
}
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
break;
+
case ZEND_JMPZ:
case ZEND_JMPNZ:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
-
- while (ZEND_OP2_JMP_ADDR(opline) < end) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
+ jmp_hitlist_count = 0;
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
if (target->opcode == ZEND_JMP) {
/* plain JMP */
/* JMPZ(X,L1), L1: JMP(L2) => JMPZ(X,L2), L1: JMP(L2) */
- CHECK_JMP(target, done_jmp_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
} else if (target->opcode == opline->opcode &&
SAME_VAR(opline->op1, target->op1)) {
/* same opcode and same var as this opcode */
/* JMPZ(X,L1), L1: JMPZ(X,L2) => JMPZ(X,L2), L1: JMPZ(X,L2) */
- CHECK_JMP2(target, done_jmp_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- } else if (target->opcode == opline->opcode + 3 &&
- SAME_VAR(opline->op1, target->op1)) {
- /* convert JMPZ(X,L1), L1: T JMPZ_EX(X,L2) to
- T = JMPZ_EX(X, L2) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- opline->opcode += 3;
- COPY_NODE(opline->result, target->result);
- break;
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
} else if (target->opcode == INV_COND(opline->opcode) &&
SAME_VAR(opline->op1, target->op1)) {
/* convert JMPZ(X,L1), L1: JMPNZ(X,L2) to
JMPZ(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == INV_COND_EX(opline->opcode) &&
+ target = target + 1;
+ } else if (target->opcode == ZEND_JMPZNZ &&
SAME_VAR(opline->op1, target->op1)) {
- /* convert JMPZ(X,L1), L1: T = JMPNZ_EX(X,L2) to
- T = JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- opline->opcode += 3;
- COPY_NODE(opline->result, target->result);
- break;
+ target = (opline->opcode == ZEND_JMPZ) ?
+ ZEND_OP2_JMP_ADDR(target) :
+ ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
} else {
break;
}
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
+ }
+
+ /* convert L: JMPZ L+1 to NOP */
+ if (target == opline + 1) {
+ if (opline->op1_type == IS_CV) {
+ opline->opcode = ZEND_CHECK_VAR;
+ opline->op2.num = 0;
+ } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
+ opline->opcode = ZEND_FREE;
+ opline->op2.num = 0;
+ } else {
+ MAKE_NOP(opline);
+ }
}
break;
case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX: {
- zend_uchar T_type = opline->result_type;
- znode_op T = opline->result;
+ case ZEND_JMPNZ_EX:
+ jmp_hitlist_count = 0;
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* plain JMP */
+ /* JMPZ_EX(X,L1), L1: JMP(L2) => JMPZ_EX(X,L2), L1: JMP(L2) */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == opline->opcode-3 &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: JMPZ(T,L2) to
+ JMPZ_EX(X,L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == opline->opcode &&
+ target->result.var == opline->result.var &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: T=JMPZ_EX(T,L2) to
+ JMPZ_EX(X,L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPZNZ &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* Check for JMPZNZ with same cond variable */
+ target = (opline->opcode == ZEND_JMPZ_EX) ?
+ ZEND_OP2_JMP_ADDR(target) :
+ ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
+ CHECK_LOOP(target);
+ } else if (target->opcode == INV_EX_COND(opline->opcode) &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: JMPNZ(T,L2) to
+ JMPZ_EX(X,L1+1) */
+ target = target + 1;
+ } else if (target->opcode == INV_EX_COND_EX(opline->opcode) &&
+ target->result.var == opline->result.var &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert T=JMPZ_EX(X,L1), L1: T=JMPNZ_EX(T,L2) to
+ JMPZ_EX(X,L1+1) */
+ target = target + 1;
+ } else if (target->opcode == ZEND_BOOL &&
+ (SAME_VAR(target->op1, opline->result) ||
+ SAME_VAR(target->op1, opline->op1))) {
+ /* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
+ Z = JMPZ_EX(X,L1+1) */
+
+ /* NOTE: This optimization pattern is not safe, but works, */
+ /* because result of JMPZ_EX instruction */
+ /* is not used on the following path and */
+ /* should be used once on the branch path. */
+ /* */
+ /* The pattern works well only if jums processed in */
+ /* direct order, otherwise it breaks JMPZ_EX */
+ /* sequences too early. */
+ opline->result.var = target->result.var;
+ target = target + 1;
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
break;
}
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
+ }
- /* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */
- /* convert L: T = JMPZ_EX T,L+1 to NOP */
- if (ZEND_OP2_JMP_ADDR(opline) == opline + 1) {
- if (opline->op1.var == opline->result.var) {
- MAKE_NOP(opline);
- } else {
- opline->opcode = ZEND_BOOL;
- SET_UNUSED(opline->op2);
- }
- goto done_jmp_optimization;
- }
-
- while (ZEND_OP2_JMP_ADDR(opline) < end) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
-
- if (target->opcode == opline->opcode-3 &&
- SAME_VAR(target->op1, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: JMPZ(T,L2) to
- JMPZ_EX(X,L2) */
- CHECK_JMP2(target, continue_jmp_ex_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- } else if (target->opcode == opline->opcode &&
- SAME_VAR(target->op1, T) &&
- SAME_VAR(target->result, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: T=JMPZ_EX(T,L2) to
- JMPZ_EX(X,L2) */
- CHECK_JMP2(target, continue_jmp_ex_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP2_JMP_ADDR(target));
- } else if (target->opcode == ZEND_JMPZNZ &&
- SAME_VAR(target->op1, T)) {
- /* Check for JMPZNZ with same cond variable */
- zend_op *new_target;
-
- CHECK_JMP2(target, continue_jmp_ex_optimization);
- if (opline->opcode == ZEND_JMPZ_EX) {
- new_target = ZEND_OP2_JMP_ADDR(target);
- } else {
- /* JMPNZ_EX */
- new_target = ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
- }
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_target);
- } else if ((target->opcode == INV_EX_COND_EX(opline->opcode) ||
- target->opcode == INV_EX_COND(opline->opcode)) &&
- SAME_VAR(opline->op1, target->op1)) {
- /* convert JMPZ_EX(X,L1), L1: JMPNZ_EX(X,L2) to
- JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == INV_EX_COND(opline->opcode) &&
- SAME_VAR(target->op1, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: JMPNZ(T,L2) to
- JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == INV_EX_COND_EX(opline->opcode) &&
- SAME_VAR(target->op1, T) &&
- SAME_VAR(target->result, T)) {
- /* convert T=JMPZ_EX(X,L1), L1: T=JMPNZ_EX(T,L2) to
- JMPZ_EX(X,L1+1) */
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else if (target->opcode == ZEND_BOOL &&
- SAME_VAR(opline->result, target->op1)) {
- /* convert Y = JMPZ_EX(X,L1), L1: Z = BOOL(Y) to
- Z = JMPZ_EX(X,L1+1) */
- opline->result.var = target->result.var;
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target + 1);
- break;
- } else {
- break;
- }
- } /* while */
-continue_jmp_ex_optimization:
- break;
-#if 0
- /* If Ti = JMPZ_EX(X, L) and Ti is not used, convert to JMPZ(X, L) */
- {
- zend_op *op;
- for(op = opline+1; op<end; op++) {
- if(op->result_type == IS_TMP_VAR &&
- op->result.var == opline->result.var) {
- break; /* can pass to part 2 */
- }
-
- if(op->opcode == ZEND_JMP ||
- op->opcode == ZEND_JMPZ ||
- op->opcode == ZEND_JMPZ_EX ||
- op->opcode == ZEND_JMPNZ ||
- op->opcode == ZEND_JMPNZ_EX ||
- op->opcode == ZEND_JMPZNZ ||
- op->opcode == ZEND_CASE ||
- op->opcode == ZEND_RETURN ||
- op->opcode == ZEND_RETURN_BY_REF ||
- op->opcode == ZEND_FAST_RET ||
- op->opcode == ZEND_FE_FETCH_R ||
- op->opcode == ZEND_FE_FETCH_RW ||
- op->opcode == ZEND_EXIT) {
- break;
- }
-
- if(op->op1_type == IS_TMP_VAR &&
- op->op1.var == opline->result.var) {
- goto done_jmp_optimization;
- }
-
- if(op->op2_type == IS_TMP_VAR &&
- op->op2.var == opline->result.var) {
- goto done_jmp_optimization;
- }
- } /* for */
-
- for(op = &op_array->opcodes[opline->op2.opline_num]; op<end; op++) {
-
- if(op->result_type == IS_TMP_VAR &&
- op->result.var == opline->result.var) {
- break; /* can pass to optimization */
- }
-
- if(op->opcode == ZEND_JMP ||
- op->opcode == ZEND_JMPZ ||
- op->opcode == ZEND_JMPZ_EX ||
- op->opcode == ZEND_JMPNZ ||
- op->opcode == ZEND_JMPNZ_EX ||
- op->opcode == ZEND_JMPZNZ ||
- op->opcode == ZEND_CASE ||
- op->opcode == ZEND_RETURN ||
- op->opcode == ZEND_RETURN_BY_REF ||
- op->opcode == ZEND_FAST_RET ||
- op->opcode == ZEND_FE_FETCH_R ||
- op->opcode == ZEND_FE_FETCH_RW ||
- op->opcode == ZEND_EXIT) {
- break;
- }
-
- if(op->op1_type == IS_TMP_VAR &&
- op->op1.var == opline->result.var) {
- goto done_jmp_optimization;
- }
-
- if(op->op2_type == IS_TMP_VAR &&
- op->op2.var == opline->result.var) {
- goto done_jmp_optimization;
- }
- }
-
- opline->opcode = opline->opcode-3; /* JMP_EX -> JMP */
- SET_UNUSED(opline->result);
- break;
- }
-#endif
+ /* convert L: T = JMPZ_EX X,L+1 to T = BOOL(X) */
+ if (target == opline + 1) {
+ opline->opcode = ZEND_BOOL;
+ opline->op2.num = 0;
}
break;
case ZEND_JMPZNZ:
- if (op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) {
- break;
- }
-
- /* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */
- while (ZEND_OP2_JMP_ADDR(opline) < end
- && ZEND_OP2_JMP_ADDR(opline)->opcode == ZEND_JMP) {
- zend_op *target = ZEND_OP2_JMP_ADDR(opline);
- CHECK_JMP(target, continue_jmpznz_optimization);
- ZEND_SET_OP_JMP_ADDR(opline, opline->op2, ZEND_OP1_JMP_ADDR(target));
- }
-continue_jmpznz_optimization:
- /* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */
- while (ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) < end
- && ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)->opcode == ZEND_JMP) {
- zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
- CHECK_JMP(target, done_jmp_optimization);
- opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, ZEND_OP1_JMP_ADDR(target));
+optimize_jmpznz:
+ jmp_hitlist_count = 0;
+ target = ZEND_OP2_JMP_ADDR(opline);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X,L1,L2), L1: JMP(L3) => JMPZNZ(X,L3,L2), L1: JMP(L3) */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if ((target->opcode == ZEND_JMPZ || target->opcode == ZEND_JMPZNZ) &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ target = target + 1;
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
+ break;
+ }
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op2, target);
}
- break;
-
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
- case ZEND_POST_INC:
- case ZEND_POST_DEC: {
- /* POST_INC, FREE => PRE_INC */
- zend_op *next_op = opline + 1;
- if (next_op >= end) {
+ jmp_hitlist_count = 0;
+ target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
+ while (1) {
+ if (target->opcode == ZEND_JMP) {
+ /* JMPZNZ(X,L1,L2), L2: JMP(L3) => JMPZNZ(X,L1,L3), L2: JMP(L3) */
+ target = ZEND_OP1_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPNZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, L1+1, L2) */
+ target = ZEND_OP2_JMP_ADDR(target);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_JMPZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ target = target + 1;
+ } else if (target->opcode == ZEND_JMPZNZ &&
+ SAME_VAR(target->op1, opline->op1)) {
+ /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> JMPZNZ(X, L3, L2) */
+ target = ZEND_OFFSET_TO_OPLINE(target, target->extended_value);
+ CHECK_LOOP(target);
+ } else if (target->opcode == ZEND_NOP) {
+ target = target + 1;
+ } else {
break;
}
- if (next_op->opcode == ZEND_FREE &&
- next_op->op1.var == opline->result.var) {
- MAKE_NOP(next_op);
- opline->opcode -= 2;
- opline->result_type = IS_UNUSED;
- }
+ opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, target);
+ }
+
+ if (ZEND_OP2_JMP_ADDR(opline) == target &&
+ !(opline->op1_type & (IS_VAR|IS_TMP_VAR))) {
+ /* JMPZNZ(?,L,L) -> JMP(L) */
+ opline->opcode = ZEND_JMP;
+ ZEND_SET_OP_JMP_ADDR(opline, opline->op1, target);
+ SET_UNUSED(opline->op1);
+ SET_UNUSED(opline->op2);
+ opline->extended_value = 0;
}
+ /* Don't convert JMPZNZ back to JMPZ/JMPNZ, because the
+ following JMP is not removed yet. */
break;
}
-done_jmp_optimization:
opline++;
- opline_num++;
}
free_alloca(jmp_hitlist, use_heap);
}
diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c
index 6f8de3d43f..0c62e1bd0d 100644
--- a/ext/opcache/Optimizer/sccp.c
+++ b/ext/opcache/Optimizer/sccp.c
@@ -740,13 +740,12 @@ static inline int ct_eval_in_array(zval *result, uint32_t extended_value, zval *
res = zend_hash_exists(ht, ZSTR_EMPTY_ALLOC());
} else {
zend_string *key;
- zval key_tmp, result_tmp;
+ zval key_tmp;
res = 0;
ZEND_HASH_FOREACH_STR_KEY(ht, key) {
ZVAL_STR(&key_tmp, key);
- compare_function(&result_tmp, op1, &key_tmp);
- if (Z_LVAL(result_tmp) == 0) {
+ if (zend_compare(op1, &key_tmp) == 0) {
res = 1;
break;
}
@@ -787,9 +786,7 @@ static inline int ct_eval_func_call(
int overflow;
if (num_args == 0) {
- if (zend_string_equals_literal(name, "get_magic_quotes_gpc")
- || zend_string_equals_literal(name, "get_magic_quotes_gpc_runtime")
- || zend_string_equals_literal(name, "php_sapi_name")
+ if (zend_string_equals_literal(name, "php_sapi_name")
|| zend_string_equals_literal(name, "imagetypes")
|| zend_string_equals_literal(name, "phpversion")) {
/* pass */
@@ -892,8 +889,7 @@ static inline int ct_eval_func_call(
} else if (zend_string_equals_literal(name, "strpos")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_STRING
- || !Z_STRLEN_P(args[1])
- || (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
+ || !Z_STRLEN_P(args[1])) {
return FAILURE;
}
/* pass */
@@ -972,8 +968,7 @@ static inline int ct_eval_func_call(
/* pass */
} else if (zend_string_equals_literal(name, "substr")) {
if (Z_TYPE_P(args[0]) != IS_STRING
- || Z_TYPE_P(args[1]) != IS_LONG
- || (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
+ || Z_TYPE_P(args[1]) != IS_LONG) {
return FAILURE;
}
/* pass */
@@ -1017,8 +1012,7 @@ static inline int ct_eval_func_call(
} else if (zend_string_equals_literal(name, "substr")) {
if (Z_TYPE_P(args[0]) != IS_STRING
|| Z_TYPE_P(args[1]) != IS_LONG
- || Z_TYPE_P(args[2]) != IS_LONG
- || (CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN)) {
+ || Z_TYPE_P(args[2]) != IS_LONG) {
return FAILURE;
}
/* pass */
@@ -2170,11 +2164,6 @@ static zval *value_from_type_and_range(sccp_ctx *ctx, int var_num, zval *tmp) {
zend_ssa *ssa = ctx->scdf.ssa;
zend_ssa_var_info *info = &ssa->var_info[var_num];
- if (ssa->vars[var_num].var >= ctx->scdf.op_array->last_var) {
- // TODO Non-CVs may cause issues with FREEs
- return NULL;
- }
-
if (info->type & MAY_BE_UNDEF) {
return NULL;
}
diff --git a/ext/opcache/Optimizer/ssa_integrity.c b/ext/opcache/Optimizer/ssa_integrity.c
index ede40be59a..4f042cae74 100644
--- a/ext/opcache/Optimizer/ssa_integrity.c
+++ b/ext/opcache/Optimizer/ssa_integrity.c
@@ -87,7 +87,7 @@ static inline zend_bool is_in_successors(zend_basic_block *block, int check) {
}
static inline zend_bool is_var_type(zend_uchar type) {
- return type == IS_CV || type == IS_VAR || type == IS_TMP_VAR;
+ return (type & (IS_CV|IS_VAR|IS_TMP_VAR)) != 0;
}
#define FAIL(...) do { \
diff --git a/ext/opcache/Optimizer/zend_call_graph.c b/ext/opcache/Optimizer/zend_call_graph.c
index 8d677c1b86..28b20d10b8 100644
--- a/ext/opcache/Optimizer/zend_call_graph.c
+++ b/ext/opcache/Optimizer/zend_call_graph.c
@@ -103,7 +103,7 @@ int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_f
case ZEND_INIT_STATIC_METHOD_CALL:
call_stack[call] = call_info;
func = zend_optimizer_get_called_func(
- script, op_array, opline, (build_flags & ZEND_RT_CONSTANTS) != 0);
+ script, op_array, opline);
if (func) {
call_info = zend_arena_calloc(arena, 1, sizeof(zend_call_info) + (sizeof(zend_send_arg_info) * ((int)opline->extended_value - 1)));
call_info->caller_op_array = op_array;
@@ -250,10 +250,8 @@ static void zend_sort_op_arrays(zend_call_graph *call_graph)
// TODO: perform topological sort of cyclic call graph
}
-int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph) /* {{{ */
+int zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph) /* {{{ */
{
- int i;
-
call_graph->op_arrays_count = 0;
if (zend_foreach_op_array(call_graph, script, zend_op_array_calc) != SUCCESS) {
return FAILURE;
@@ -264,13 +262,20 @@ int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t buil
if (zend_foreach_op_array(call_graph, script, zend_op_array_collect) != SUCCESS) {
return FAILURE;
}
+
+ return SUCCESS;
+}
+/* }}} */
+
+void zend_analyze_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph) /* {{{ */
+{
+ int i;
+
for (i = 0; i < call_graph->op_arrays_count; i++) {
- zend_analyze_calls(arena, script, build_flags, call_graph->op_arrays[i], call_graph->func_infos + i);
+ zend_analyze_calls(arena, script, 0, call_graph->op_arrays[i], call_graph->func_infos + i);
}
zend_analyze_recursion(call_graph);
zend_sort_op_arrays(call_graph);
-
- return SUCCESS;
}
/* }}} */
diff --git a/ext/opcache/Optimizer/zend_call_graph.h b/ext/opcache/Optimizer/zend_call_graph.h
index 033c675b63..8d2b866fd0 100644
--- a/ext/opcache/Optimizer/zend_call_graph.h
+++ b/ext/opcache/Optimizer/zend_call_graph.h
@@ -69,7 +69,8 @@ typedef struct _zend_call_graph {
BEGIN_EXTERN_C()
-int zend_build_call_graph(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_call_graph *call_graph);
+int zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph);
+void zend_analyze_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph);
zend_call_info **zend_build_call_map(zend_arena **arena, zend_func_info *info, zend_op_array *op_array);
int zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info);
diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c
index 66c15be311..c5b1b53a0e 100644
--- a/ext/opcache/Optimizer/zend_cfg.c
+++ b/ext/opcache/Optimizer/zend_cfg.c
@@ -93,7 +93,7 @@ static void zend_mark_reachable(zend_op *opcodes, zend_cfg *cfg, zend_basic_bloc
b = succ;
break;
} else {
- /* Recusively check reachability */
+ /* Recursively check reachability */
if (!(succ->flags & ZEND_BB_REACHABLE)) {
zend_mark_reachable(opcodes, cfg, succ);
}
diff --git a/ext/opcache/Optimizer/zend_cfg.h b/ext/opcache/Optimizer/zend_cfg.h
index 7d6ef25eee..51e2e63b4b 100644
--- a/ext/opcache/Optimizer/zend_cfg.h
+++ b/ext/opcache/Optimizer/zend_cfg.h
@@ -22,7 +22,7 @@
/* zend_basic_bloc.flags */
#define ZEND_BB_START (1<<0) /* fist block */
#define ZEND_BB_FOLLOW (1<<1) /* follows the next block */
-#define ZEND_BB_TARGET (1<<2) /* jump taget */
+#define ZEND_BB_TARGET (1<<2) /* jump target */
#define ZEND_BB_EXIT (1<<3) /* without successors */
#define ZEND_BB_ENTRY (1<<4) /* stackless entry */
#define ZEND_BB_TRY (1<<5) /* start of try block */
@@ -92,7 +92,6 @@ typedef struct _zend_cfg {
} zend_cfg;
/* Build Flags */
-#define ZEND_RT_CONSTANTS (1U<<31)
#define ZEND_CFG_STACKLESS (1<<30)
#define ZEND_SSA_DEBUG_LIVENESS (1<<29)
#define ZEND_SSA_DEBUG_PHI_PLACEMENT (1<<28)
@@ -102,15 +101,15 @@ typedef struct _zend_cfg {
#define ZEND_CALL_TREE (1<<23)
#define ZEND_SSA_USE_CV_RESULTS (1<<22)
-#define CRT_CONSTANT_EX(op_array, opline, node, rt_constants) \
- ((rt_constants) ? \
+#define CRT_CONSTANT_EX(op_array, opline, node) \
+ (((op_array)->fn_flags & ZEND_ACC_DONE_PASS_TWO) ? \
RT_CONSTANT(opline, (node)) \
: \
CT_CONSTANT_EX(op_array, (node).constant) \
)
#define CRT_CONSTANT(node) \
- CRT_CONSTANT_EX(op_array, opline, node, (build_flags & ZEND_RT_CONSTANTS))
+ CRT_CONSTANT_EX(op_array, opline, node)
#define RETURN_VALUE_USED(opline) \
((opline)->result_type != IS_UNUSED)
diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c
index e995b673b7..3bb76fb05c 100644
--- a/ext/opcache/Optimizer/zend_dfg.c
+++ b/ext/opcache/Optimizer/zend_dfg.c
@@ -123,10 +123,6 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_LIST_W:
case ZEND_VERIFY_RETURN_TYPE:
case ZEND_PRE_INC_OBJ:
diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c
index d6ef63415a..59288fabdd 100644
--- a/ext/opcache/Optimizer/zend_dump.c
+++ b/ext/opcache/Optimizer/zend_dump.c
@@ -127,11 +127,8 @@ static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t fla
} else if (ZEND_VM_OP_CONSTRUCTOR == (flags & ZEND_VM_OP_MASK)) {
fprintf(stderr, " CONSTRUCTOR");
} else if (ZEND_VM_OP_CONST_FETCH == (flags & ZEND_VM_OP_MASK)) {
- if (op.num & IS_CONSTANT_UNQUALIFIED) {
- fprintf(stderr, " (unqualified)");
- }
- if (op.num & IS_CONSTANT_IN_NAMESPACE) {
- fprintf(stderr, " (in-namespace)");
+ if (op.num & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
+ fprintf(stderr, " (unqualified-in-namespace)");
}
}
}
@@ -142,7 +139,7 @@ void zend_dump_var(const zend_op_array *op_array, zend_uchar var_type, int var_n
fprintf(stderr, "CV%d($%s)", var_num, op_array->vars[var_num]->val);
} else if (var_type == IS_VAR) {
fprintf(stderr, "V%d", var_num);
- } else if (var_type == IS_TMP_VAR) {
+ } else if ((var_type & (IS_VAR|IS_TMP_VAR)) == IS_TMP_VAR) {
fprintf(stderr, "T%d", var_num);
} else {
fprintf(stderr, "X%d", var_num);
@@ -314,10 +311,6 @@ static void zend_dump_type_info(uint32_t info, zend_class_entry *ce, int is_inst
fprintf(stderr, "resource");
}
}
- if (info & MAY_BE_ERROR) {
- if (first) first = 0; else fprintf(stderr, ", ");
- fprintf(stderr, "error");
- }
//TODO: this is useful only for JIT???
if (info & MAY_BE_IN_REG) {
if (first) first = 0; else fprintf(stderr, ", ");
@@ -409,23 +402,17 @@ static void zend_dump_range_constraint(const zend_op_array *op_array, const zend
}
}
-static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data)
+void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data)
{
const char *name = zend_get_opcode_name(opline->opcode);
uint32_t flags = zend_get_opcode_flags(opline->opcode);
uint32_t n = 0;
- int len = 0;
const zend_ssa *ssa = NULL;
if (dump_flags & ZEND_DUMP_SSA) {
ssa = (const zend_ssa*)data;
}
- if (!b) {
- len = fprintf(stderr, "L%u (%u):", (uint32_t)(opline - op_array->opcodes), opline->lineno);
- }
- fprintf(stderr, "%*c", 12-len, ' ');
-
if (!ssa || !ssa->ops || ssa->ops[opline - op_array->opcodes].result_use < 0) {
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
if (ssa && ssa->ops && ssa->ops[opline - op_array->opcodes].result_def >= 0) {
@@ -523,7 +510,8 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
fprintf(stderr, " (bool)");
break;
default:
- fprintf(stderr, " (\?\?\?)");
+ fprintf(stderr, " TYPE");
+ zend_dump_type_info(opline->extended_value, NULL, 0, dump_flags);
break;
}
} else if (ZEND_VM_EXT_EVAL == (flags & ZEND_VM_EXT_MASK)) {
@@ -581,20 +569,18 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
fprintf(stderr, " (ref)");
}
}
- if ((ZEND_VM_EXT_DIM_OBJ_WRITE|ZEND_VM_EXT_FETCH_REF) & flags) {
+ if ((ZEND_VM_EXT_DIM_WRITE|ZEND_VM_EXT_FETCH_REF) & flags) {
uint32_t obj_flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
if (obj_flags == ZEND_FETCH_REF) {
fprintf(stderr, " (ref)");
} else if (obj_flags == ZEND_FETCH_DIM_WRITE) {
fprintf(stderr, " (dim write)");
- } else if (obj_flags == ZEND_FETCH_OBJ_WRITE) {
- fprintf(stderr, " (obj write)");
}
}
}
if (opline->op1_type == IS_CONST) {
- zend_dump_const(CRT_CONSTANT_EX(op_array, opline, opline->op1, (dump_flags & ZEND_DUMP_RT_CONSTANTS)));
+ zend_dump_const(CRT_CONSTANT(opline->op1));
} else if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
if (ssa && ssa->ops) {
int ssa_var_num = ssa->ops[opline - op_array->opcodes].op1_use;
@@ -619,7 +605,9 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
} else {
uint32_t op1_flags = ZEND_VM_OP1_FLAGS(flags);
if (ZEND_VM_OP_JMP_ADDR == (op1_flags & ZEND_VM_OP_MASK)) {
- if (b) {
+ if (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) {
+ fprintf(stderr, " %04u", (uint32_t)(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes));
+ } else if (b) {
fprintf(stderr, " BB%d", b->successors[n++]);
} else {
fprintf(stderr, " L%u", (uint32_t)(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes));
@@ -630,7 +618,7 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
}
if (opline->op2_type == IS_CONST) {
- zval *op = CRT_CONSTANT_EX(op_array, opline, opline->op2, (dump_flags & ZEND_DUMP_RT_CONSTANTS));
+ zval *op = CRT_CONSTANT(opline->op2);
if (opline->opcode == ZEND_SWITCH_LONG || opline->opcode == ZEND_SWITCH_STRING) {
HashTable *jumptable = Z_ARRVAL_P(op);
zend_string *key;
@@ -642,7 +630,9 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
} else {
fprintf(stderr, " " ZEND_LONG_FMT ":", num_key);
}
- if (b) {
+ if (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) {
+ fprintf(stderr, " %04u,", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
+ } else if (b) {
fprintf(stderr, " BB%d,", b->successors[n++]);
} else {
fprintf(stderr, " L%u,", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, Z_LVAL_P(zv)));
@@ -677,7 +667,9 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
uint32_t op2_flags = ZEND_VM_OP2_FLAGS(flags);
if (ZEND_VM_OP_JMP_ADDR == (op2_flags & ZEND_VM_OP_MASK)) {
if (opline->opcode != ZEND_CATCH || !(opline->extended_value & ZEND_LAST_CATCH)) {
- if (b) {
+ if (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) {
+ fprintf(stderr, " %04u", (uint32_t)(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes));
+ } else if (b) {
fprintf(stderr, " BB%d", b->successors[n++]);
} else {
fprintf(stderr, " L%u", (uint32_t)(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes));
@@ -689,14 +681,22 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
}
if (ZEND_VM_EXT_JMP_ADDR == (flags & ZEND_VM_EXT_MASK)) {
- if (b) {
+ if (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) {
+ fprintf(stderr, " %04u", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
+ } else if (b) {
fprintf(stderr, " BB%d", b->successors[n++]);
} else {
fprintf(stderr, " L%u", (uint32_t)ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value));
}
}
if (opline->result_type == IS_CONST) {
- zend_dump_const(CRT_CONSTANT_EX(op_array, opline, opline->result, (dump_flags & ZEND_DUMP_RT_CONSTANTS)));
+ zend_dump_const(CRT_CONSTANT(opline->result));
+#if 0
+ } else if (opline->result_type & IS_SMART_BRANCH_JMPZ) {
+ fprintf(stderr, " jmpz");
+ } else if (opline->result_type & IS_SMART_BRANCH_JMPNZ) {
+ fprintf(stderr, " jmpnz");
+#endif
} else if (ssa && ssa->ops && ssa->ops[opline - op_array->opcodes].result_use >= 0) {
if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
if (ssa && ssa->ops) {
@@ -718,6 +718,20 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *
}
}
}
+}
+
+static void zend_dump_op_line(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data)
+{
+ int len = 0;
+
+ if (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) {
+ len = fprintf(stderr, "%04u:", (uint32_t)(opline - op_array->opcodes));
+ } else if (!b) {
+ len = fprintf(stderr, "L%u (%u):", (uint32_t)(opline - op_array->opcodes), opline->lineno);
+ }
+ fprintf(stderr, "%*c", 12-len, ' ');
+
+ zend_dump_op(op_array, b, opline, dump_flags, data);
fprintf(stderr, "\n");
}
@@ -729,6 +743,9 @@ static void zend_dump_block_info(const zend_cfg *cfg, int n, uint32_t dump_flags
if (b->flags & ZEND_BB_START) {
fprintf(stderr, " start");
}
+ if (b->flags & ZEND_BB_RECV_ENTRY) {
+ fprintf(stderr, " recv");
+ }
if (b->flags & ZEND_BB_FOLLOW) {
fprintf(stderr, " follow");
}
@@ -996,7 +1013,7 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons
opline = op_array->opcodes + b->start;
end = opline + b->len;
while (opline < end) {
- zend_dump_op(op_array, b, opline, dump_flags, data);
+ zend_dump_op_line(op_array, b, opline, dump_flags, data);
opline++;
}
}
@@ -1004,7 +1021,10 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons
if (op_array->last_live_range && (dump_flags & ZEND_DUMP_LIVE_RANGES)) {
fprintf(stderr, "LIVE RANGES:\n");
for (i = 0; i < op_array->last_live_range; i++) {
- fprintf(stderr, " %u: L%u - L%u ",
+ fprintf(stderr,
+ (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) ?
+ " %u: %04u - %04u " :
+ " %u: L%u - L%u ",
EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
op_array->live_range[i].start,
op_array->live_range[i].end);
@@ -1057,13 +1077,16 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons
const zend_op *end = opline + op_array->last;
while (opline < end) {
- zend_dump_op(op_array, NULL, opline, dump_flags, data);
+ zend_dump_op_line(op_array, NULL, opline, dump_flags, data);
opline++;
}
if (op_array->last_live_range && (dump_flags & ZEND_DUMP_LIVE_RANGES)) {
fprintf(stderr, "LIVE RANGES:\n");
for (i = 0; i < op_array->last_live_range; i++) {
- fprintf(stderr, " %u: L%u - L%u ",
+ fprintf(stderr,
+ (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) ?
+ " %u: %04u - %04u " :
+ " %u: L%u - L%u ",
EX_VAR_TO_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK),
op_array->live_range[i].start,
op_array->live_range[i].end);
@@ -1089,22 +1112,35 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons
if (op_array->last_try_catch) {
fprintf(stderr, "EXCEPTION TABLE:\n");
for (i = 0; i < op_array->last_try_catch; i++) {
- fprintf(stderr, " L%u",
+ fprintf(stderr,
+ (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) ?
+ " %04u" :
+ " L%u",
op_array->try_catch_array[i].try_op);
+
if (op_array->try_catch_array[i].catch_op) {
- fprintf(stderr, ", L%u",
+ fprintf(stderr,
+ (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) ?
+ ", %04u" :
+ ", L%u",
op_array->try_catch_array[i].catch_op);
} else {
fprintf(stderr, ", -");
}
if (op_array->try_catch_array[i].finally_op) {
- fprintf(stderr, ", L%u",
+ fprintf(stderr,
+ (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) ?
+ ", %04u" :
+ ", L%u",
op_array->try_catch_array[i].finally_op);
} else {
fprintf(stderr, ", -");
}
if (op_array->try_catch_array[i].finally_end) {
- fprintf(stderr, ", L%u\n",
+ fprintf(stderr,
+ (dump_flags & ZEND_DUMP_NUMERIC_OPLINES) ?
+ ", %04u" :
+ ", L%u\n",
op_array->try_catch_array[i].finally_end);
} else {
fprintf(stderr, ", -\n");
diff --git a/ext/opcache/Optimizer/zend_dump.h b/ext/opcache/Optimizer/zend_dump.h
index 820f3daf19..5f1968fd23 100644
--- a/ext/opcache/Optimizer/zend_dump.h
+++ b/ext/opcache/Optimizer/zend_dump.h
@@ -27,11 +27,12 @@
#define ZEND_DUMP_CFG (1<<2)
#define ZEND_DUMP_SSA (1<<3)
#define ZEND_DUMP_LIVE_RANGES (1<<4)
-#define ZEND_DUMP_RT_CONSTANTS ZEND_RT_CONSTANTS
+#define ZEND_DUMP_NUMERIC_OPLINES (1<<5)
BEGIN_EXTERN_C()
void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data);
+void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const void *data);
void zend_dump_dominators(const zend_op_array *op_array, const zend_cfg *cfg);
void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg);
void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa);
diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c
index ce23207de9..b57e5e65ef 100644
--- a/ext/opcache/Optimizer/zend_func_info.c
+++ b/ext/opcache/Optimizer/zend_func_info.c
@@ -39,66 +39,19 @@ typedef struct _func_info_t {
info_func_t info_func;
} func_info_t;
-/* MSVC defines its own IN macro, undefine it here */
-#undef IN
-
#define F0(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | (info)), NULL}
+ {name, sizeof(name)-1, (info), NULL}
#define F1(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_RC1 | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_RC1 | (info)), NULL}
#define FN(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
#define FR(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_REF | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_REF | (info)), NULL}
#define FX(name, info) \
- {name, sizeof(name)-1, (FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | (info)), NULL}
-#define I0(name, info) \
- {name, sizeof(name)-1, (info), NULL}
-#define I1(name, info) \
- {name, sizeof(name)-1, (MAY_BE_RC1 | (info)), NULL}
-#define IN(name, info) \
- {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | (info)), NULL}
+ {name, sizeof(name)-1, (MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | (info)), NULL}
#define FC(name, callback) \
{name, sizeof(name)-1, 0, callback}
-static uint32_t zend_strlen_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
- uint32_t tmp = 0;
- if (call_info->arg_info[0].opline) {
- uint32_t arg_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
-
- if (arg_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_LONG;
- }
- if (arg_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- } else {
- tmp |= MAY_BE_LONG | FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else if (call_info->num_args != -1) {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL;
- } else {
- return MAY_BE_LONG | FUNC_MAY_WARN | MAY_BE_NULL;
- }
-}
-
-static uint32_t zend_dechex_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
- return MAY_BE_RC1 | MAY_BE_STRING;
- } else if (call_info->num_args != -1) {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL;
- } else {
- return FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_STRING | MAY_BE_NULL;
- }
-}
-
static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa *ssa)
{
if (call_info->num_args == 2 || call_info->num_args == 3) {
@@ -106,7 +59,7 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
uint32_t t1 = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
uint32_t t2 = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[1].opline);
uint32_t t3 = 0;
- uint32_t tmp = FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG;
+ uint32_t tmp = MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG;
if (call_info->num_args == 3) {
t3 = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[2].opline);
@@ -127,87 +80,7 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
return tmp;
} else {
/* may warning, and return FALSE */
- return FUNC_MAY_WARN | MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
- }
-}
-
-static uint32_t zend_is_type_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
- return MAY_BE_FALSE | MAY_BE_TRUE;
- } else {
- return MAY_BE_FALSE | MAY_BE_TRUE | FUNC_MAY_WARN;
- }
-}
-
-static uint32_t zend_l_ss_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 2) {
-
- uint32_t arg1_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
- uint32_t arg2_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[1].opline);
- uint32_t tmp = 0;
-
- if ((arg1_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) &&
- (arg2_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT))) {
- tmp |= MAY_BE_LONG;
- }
- if ((arg1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
- (arg2_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL | MAY_BE_LONG;
- }
-}
-
-static uint32_t zend_lb_ssn_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 3) {
- uint32_t arg1_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
- uint32_t arg2_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[1].opline);
- uint32_t arg3_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[2].opline);
- uint32_t tmp = 0;
-
- if ((arg1_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) &&
- (arg2_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) &&
- (arg3_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT))) {
- tmp |= MAY_BE_LONG | MAY_BE_FALSE;
- }
- if ((arg1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
- (arg2_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
- (arg3_info & (MAY_BE_STRING|MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL | MAY_BE_LONG;
- }
-}
-
-static uint32_t zend_b_s_info(const zend_call_info *call_info, const zend_ssa *ssa)
-{
- if (call_info->num_args == 1) {
-
- uint32_t arg1_info = _ssa_op1_info(call_info->caller_op_array, ssa, call_info->arg_info[0].opline);
- uint32_t tmp = 0;
-
- if (arg1_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_FALSE | MAY_BE_TRUE;
- }
- if (arg1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- /* warning, and returns NULL */
- tmp |= FUNC_MAY_WARN | MAY_BE_NULL;
- }
- return tmp;
- } else {
- /* warning, and returns NULL */
- return FUNC_MAY_WARN | MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE;
+ return MAY_BE_RC1 | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
}
}
@@ -215,729 +88,379 @@ static uint32_t zend_b_s_info(const zend_call_info *call_info, const zend_ssa *s
static const func_info_t func_infos[] = {
/* zend */
- I1("zend_version", MAY_BE_STRING),
- I0("gc_collect_cycles", MAY_BE_LONG),
- I0("gc_enabled", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("gc_enable", MAY_BE_NULL),
- F0("gc_disable", MAY_BE_NULL),
- F0("func_num_args", MAY_BE_LONG),
+ F1("zend_version", MAY_BE_STRING),
FN("func_get_arg", UNKNOWN_INFO),
F1("func_get_args", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
- FC("strlen", zend_strlen_info),
- FC("strcmp", zend_l_ss_info),
- FC("strncmp", zend_lb_ssn_info),
- FC("strcasecmp", zend_l_ss_info),
- FC("strncasecmp", zend_lb_ssn_info),
- F1("each", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_KEY_ANY),
- F0("error_reporting", MAY_BE_NULL | MAY_BE_LONG),
- F0("define", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_NULL), // TODO: inline
- FC("defined", zend_b_s_info), // TODO: inline
- FN("get_class", MAY_BE_FALSE | MAY_BE_STRING),
- FN("get_called_class", MAY_BE_FALSE | MAY_BE_STRING),
- FN("get_parent_class", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_NULL),
- F0("is_subclass_of", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline
- F0("is_a", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline
- F1("get_class_vars", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- FN("get_object_vars", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- FN("get_mangled_object_vars", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- F1("get_class_methods", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("method_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("property_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("class_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("interface_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("trait_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FC("function_exists", zend_b_s_info), // TODO: inline
- F0("class_alias", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("get_included_files", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("trigger_error", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("user_error", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("get_class_vars", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ FN("get_object_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ FN("get_mangled_object_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ F1("get_class_methods", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_included_files", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
FN("set_error_handler", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_OBJECT | MAY_BE_OBJECT),
- I0("restore_error_handler", MAY_BE_TRUE),
- I0("restore_exception_handler", MAY_BE_TRUE),
- I1("get_declared_traits", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- I1("get_declared_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- I1("get_declared_interfaces", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("get_defined_functions", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
- I1("get_defined_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
- FN("create_function", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("get_resource_type", MAY_BE_NULL | MAY_BE_STRING),
- F1("get_defined_constants", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_RESOURCE | MAY_BE_ARRAY_OF_ARRAY),
- F0("debug_print_backtrace", MAY_BE_NULL),
- F1("debug_backtrace", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
- F1("get_loaded_extensions", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- FC("extension_loaded", zend_b_s_info),
- F1("get_extension_funcs", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F0("restore_error_handler", MAY_BE_TRUE),
+ F0("restore_exception_handler", MAY_BE_TRUE),
+ F1("get_declared_traits", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_declared_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_declared_interfaces", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_defined_functions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("get_defined_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
+ F1("get_resource_type", MAY_BE_STRING),
+ F1("get_defined_constants", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_RESOURCE | MAY_BE_ARRAY_OF_ARRAY),
+ F1("debug_backtrace", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
+ F1("get_loaded_extensions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("get_extension_funcs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
/* ext/standard */
FN("constant", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING | MAY_BE_RESOURCE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- F1("bin2hex", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("hex2bin", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("sleep", MAY_BE_FALSE | MAY_BE_LONG),
- F0("usleep", MAY_BE_NULL | MAY_BE_FALSE),
+ F1("bin2hex", MAY_BE_STRING),
+ F1("hex2bin", MAY_BE_FALSE | MAY_BE_STRING),
#if HAVE_NANOSLEEP
- F0("time_nanosleep", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
- F0("time_sleep_until", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("time_nanosleep", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#if HAVE_STRPTIME
- F1("strptime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("strptime", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
- F0("flush", MAY_BE_NULL),
- F1("wordwrap", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("htmlspecialchars", MAY_BE_NULL | MAY_BE_STRING),
- F1("htmlentities", MAY_BE_NULL | MAY_BE_STRING),
- FN("html_entity_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("htmlspecialchars_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("get_html_translation_table", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F1("sha1", MAY_BE_NULL | MAY_BE_STRING),
- F1("sha1_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("md5", MAY_BE_NULL | MAY_BE_STRING),
- F1("md5_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("crc32", MAY_BE_NULL | MAY_BE_LONG),
- F1("iptcparse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F1("iptcembed", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("getimagesize", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("getimagesizefromstring", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("image_type_to_mime_type", MAY_BE_NULL | MAY_BE_STRING),
+ F1("wordwrap", MAY_BE_STRING),
+ F1("htmlspecialchars", MAY_BE_STRING),
+ F1("htmlentities", MAY_BE_STRING),
+ F1("get_html_translation_table", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
+ F1("sha1", MAY_BE_STRING),
+ F1("sha1_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("md5", MAY_BE_STRING),
+ F1("md5_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("iptcparse", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("iptcembed", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("getimagesize", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("getimagesizefromstring", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("image_type_to_mime_type", MAY_BE_STRING),
F1("image_type_to_extension", MAY_BE_FALSE | MAY_BE_STRING),
- F0("phpinfo", MAY_BE_NULL | MAY_BE_TRUE),
- F1("phpversion", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("phpcredits", MAY_BE_NULL | MAY_BE_TRUE),
- I1("php_sapi_name", MAY_BE_FALSE | MAY_BE_STRING),
- F1("php_uname", MAY_BE_NULL | MAY_BE_STRING),
- I1("php_ini_scanned_files", MAY_BE_FALSE | MAY_BE_STRING),
- I1("php_ini_loaded_file", MAY_BE_FALSE | MAY_BE_STRING),
- F0("strnatcmp", MAY_BE_NULL | MAY_BE_LONG),
- F0("strnatcasecmp", MAY_BE_NULL | MAY_BE_LONG),
- F0("substr_count", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strspn", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strcspn", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("strtok", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("strtoupper", MAY_BE_NULL | MAY_BE_STRING),
- FN("strtolower", MAY_BE_NULL | MAY_BE_STRING),
- F0("strpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("stripos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strrpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("strripos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("strrev", MAY_BE_NULL | MAY_BE_STRING),
- F1("hebrev", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("hebrevc", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("nl2br", MAY_BE_NULL | MAY_BE_STRING),
- F1("basename", MAY_BE_NULL | MAY_BE_STRING),
- F1("dirname", MAY_BE_NULL | MAY_BE_STRING),
- F1("pathinfo", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F1("stripslashes", MAY_BE_NULL | MAY_BE_STRING),
- F1("stripcslashes", MAY_BE_NULL | MAY_BE_STRING),
- F1("strstr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("stristr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("strrchr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("str_shuffle", MAY_BE_NULL | MAY_BE_STRING),
- F1("str_word_count", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("str_split", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F0("phpinfo", MAY_BE_TRUE),
+ F1("phpversion", MAY_BE_FALSE | MAY_BE_STRING),
+ F0("phpcredits", MAY_BE_TRUE),
+ F1("php_sapi_name", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("php_uname", MAY_BE_STRING),
+ F1("php_ini_scanned_files", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("php_ini_loaded_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("strtok", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("strrev", MAY_BE_STRING),
+ F1("hebrev", MAY_BE_STRING),
+ F1("basename", MAY_BE_STRING),
+ F1("dirname", MAY_BE_STRING),
+ F1("pathinfo", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
+ F1("stripslashes", MAY_BE_STRING),
+ F1("stripcslashes", MAY_BE_STRING),
+ F1("strstr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("stristr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("strrchr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("str_shuffle", MAY_BE_STRING),
+ F1("str_word_count", MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("str_split", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("strpbrk", MAY_BE_FALSE | MAY_BE_STRING),
- F0("substr_compare", MAY_BE_FALSE | MAY_BE_LONG),
- F0("strcoll", MAY_BE_NULL | MAY_BE_LONG),
-#ifdef HAVE_STRFMON
- F1("money_format", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
-#endif
- FN("substr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("substr_replace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
- F1("quotemeta", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("ucfirst", MAY_BE_NULL | MAY_BE_STRING),
- FN("lcfirst", MAY_BE_NULL | MAY_BE_STRING),
- F1("ucwords", MAY_BE_NULL | MAY_BE_STRING),
- FN("strtr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("addslashes", MAY_BE_NULL | MAY_BE_STRING),
- F1("addcslashes", MAY_BE_NULL | MAY_BE_STRING),
- FN("rtrim", MAY_BE_NULL | MAY_BE_STRING),
- FN("str_replace", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
- FN("str_ireplace", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
- F1("str_repeat", MAY_BE_NULL | MAY_BE_STRING),
- F1("count_chars", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("chunk_split", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("trim", MAY_BE_NULL | MAY_BE_STRING),
- FN("ltrim", MAY_BE_NULL | MAY_BE_STRING),
- F1("strip_tags", MAY_BE_NULL | MAY_BE_STRING),
- F0("similar_text", MAY_BE_NULL | MAY_BE_LONG),
- F1("explode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- FN("implode", MAY_BE_NULL | MAY_BE_STRING),
- FN("join", MAY_BE_NULL | MAY_BE_STRING),
- FN("setlocale", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ FN("substr_replace", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
+ F1("quotemeta", MAY_BE_STRING),
+ F1("ucwords", MAY_BE_STRING),
+ F1("addcslashes", MAY_BE_STRING),
+ FN("str_replace", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
+ FN("str_ireplace", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY | MAY_BE_ARRAY_OF_OBJECT),
+ F1("str_repeat", MAY_BE_STRING),
+ F1("count_chars", MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("chunk_split", MAY_BE_STRING),
+ F1("strip_tags", MAY_BE_STRING),
+ F1("explode", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("localeconv", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#if HAVE_NL_LANGINFO
- F1("nl_langinfo", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("nl_langinfo", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- F1("soundex", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("levenshtein", MAY_BE_NULL | MAY_BE_LONG),
- F1("chr", MAY_BE_NULL | MAY_BE_STRING),
- F0("ord", MAY_BE_NULL | MAY_BE_LONG),
- F0("parse_str", MAY_BE_NULL),
- F1("str_getcsv", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
- F1("str_pad", MAY_BE_NULL | MAY_BE_STRING),
- F1("chop", MAY_BE_NULL | MAY_BE_STRING),
- F1("strchr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("sprintf", MAY_BE_FALSE | MAY_BE_STRING),
- F0("printf", MAY_BE_FALSE | MAY_BE_LONG),
- F0("vprintf", MAY_BE_FALSE | MAY_BE_LONG),
- F1("vsprintf", MAY_BE_FALSE | MAY_BE_STRING),
- F0("fprintf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("vfprintf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F1("soundex", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("chr", MAY_BE_STRING),
+ F1("str_getcsv", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
+ F1("strchr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sprintf", MAY_BE_STRING),
+ F1("vsprintf", MAY_BE_STRING),
F1("sscanf", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("fscanf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
F1("parse_url", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_LONG),
- F1("urlencode", MAY_BE_NULL | MAY_BE_STRING),
- F1("urldecode", MAY_BE_NULL | MAY_BE_STRING),
- F1("rawurlencode", MAY_BE_NULL | MAY_BE_STRING),
- F1("rawurldecode", MAY_BE_NULL | MAY_BE_STRING),
+ F1("urlencode", MAY_BE_STRING),
+ F1("urldecode", MAY_BE_STRING),
+ F1("rawurlencode", MAY_BE_STRING),
+ F1("rawurldecode", MAY_BE_STRING),
F1("http_build_query", MAY_BE_FALSE | MAY_BE_STRING),
#if defined(HAVE_SYMLINK) || defined(PHP_WIN32)
- F1("readlink", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("linkinfo", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("symlink", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("link", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("readlink", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- F0("unlink", MAY_BE_FALSE | MAY_BE_TRUE),
F1("exec", MAY_BE_FALSE | MAY_BE_STRING),
F1("system", MAY_BE_FALSE | MAY_BE_STRING),
- F1("escapeshellcmd", MAY_BE_NULL | MAY_BE_STRING),
- F1("escapeshellarg", MAY_BE_NULL | MAY_BE_STRING),
+ F1("escapeshellcmd", MAY_BE_STRING),
+ F1("escapeshellarg", MAY_BE_STRING),
F1("passthru", MAY_BE_NULL | MAY_BE_FALSE),
F1("shell_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
#ifdef PHP_CAN_SUPPORT_PROC_OPEN
F1("proc_open", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("proc_close", MAY_BE_FALSE | MAY_BE_LONG),
- F0("proc_terminate", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("proc_get_status", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
-#endif
-#ifdef HAVE_NICE
- F0("proc_nice", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("proc_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
- F0("rand", MAY_BE_NULL | MAY_BE_LONG),
F1("random_bytes", MAY_BE_STRING),
- F1("random_int", MAY_BE_LONG),
- F0("srand", MAY_BE_NULL),
- F0("getrandmax", MAY_BE_NULL | MAY_BE_LONG),
- F0("mt_rand", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("mt_srand", MAY_BE_NULL),
- I0("mt_getrandmax", MAY_BE_LONG),
-#if HAVE_GETSERVBYNAME
- F0("getservbyname", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
-#endif
#if HAVE_GETSERVBYPORT
- F1("getservbyport", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
-#endif
-#if HAVE_GETPROTOBYNAME
- F0("getprotobyname", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F1("getservbyport", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if HAVE_GETPROTOBYNUMBER
- F1("getprotobynumber", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("getprotobynumber", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- F0("getmyuid", MAY_BE_FALSE | MAY_BE_LONG),
- F0("getmygid", MAY_BE_FALSE | MAY_BE_LONG),
- F0("getmypid", MAY_BE_FALSE | MAY_BE_LONG),
- F0("getmyinode", MAY_BE_FALSE | MAY_BE_LONG),
- F0("getlastmod", MAY_BE_FALSE | MAY_BE_LONG),
- F1("base64_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("base64_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("password_hash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("password_get_info", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F0("password_needs_rehash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("password_verify", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("base64_decode", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("base64_encode", MAY_BE_STRING),
+ F1("password_hash", MAY_BE_STRING),
+ F1("password_get_info", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("convert_uuencode", MAY_BE_FALSE | MAY_BE_STRING),
F1("convert_uudecode", MAY_BE_FALSE | MAY_BE_STRING),
- F0("abs", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("ceil", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("floor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("round", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("sin", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("cos", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("tan", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("asin", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("acos", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("atan", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("atanh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("atan2", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("sinh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("cosh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("tanh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("asinh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("acosh", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("expm1", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("log1p", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("pi", MAY_BE_DOUBLE),
- F0("is_finite", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_nan", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_infinite", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("pow", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("exp", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("log", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("log10", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("sqrt", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("hypot", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("deg2rad", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("rad2deg", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("bindec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("hexdec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("octdec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE),
- F1("decbin", MAY_BE_NULL | MAY_BE_STRING),
- F1("decoct", MAY_BE_NULL | MAY_BE_STRING),
- FC("dechex", zend_dechex_info),
- F1("base_convert", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("number_format", MAY_BE_NULL | MAY_BE_STRING),
- F0("fmod", MAY_BE_NULL | MAY_BE_DOUBLE),
+ F1("pow", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_OBJECT),
+ F1("decbin", MAY_BE_STRING),
+ F1("decoct", MAY_BE_STRING),
+ F1("dechex", MAY_BE_STRING),
+ F1("base_convert", MAY_BE_STRING),
+ F1("number_format", MAY_BE_STRING),
#ifdef HAVE_INET_NTOP
F1("inet_ntop", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#ifdef HAVE_INET_PTON
F1("inet_pton", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- F0("ip2long", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("long2ip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("long2ip", MAY_BE_FALSE | MAY_BE_STRING),
F1("getenv", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_PUTENV
- F0("putenv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
#endif
F1("getopt", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#ifdef HAVE_GETLOADAVG
F1("sys_getloadavg", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
#endif
#ifdef HAVE_GETTIMEOFDAY
- F1("microtime", MAY_BE_NULL | MAY_BE_DOUBLE | MAY_BE_STRING),
- F1("gettimeofday", MAY_BE_NULL | MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
+ F1("microtime", MAY_BE_DOUBLE | MAY_BE_STRING),
+ F1("gettimeofday", MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#ifdef HAVE_GETRUSAGE
- F1("getrusage", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
+ F1("getrusage", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
#endif
#ifdef HAVE_GETTIMEOFDAY
- F1("uniqid", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("uniqid", MAY_BE_STRING),
#endif
- F1("quoted_printable_decode", MAY_BE_NULL | MAY_BE_STRING),
- F1("quoted_printable_encode", MAY_BE_NULL | MAY_BE_STRING),
- F1("convert_cyr_string", MAY_BE_NULL | MAY_BE_STRING),
- I1("get_current_user", MAY_BE_STRING),
- F0("set_time_limit", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("header_register_callback", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("get_cfg_var", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- I0("magic_quotes_runtime", MAY_BE_FALSE),
- I0("set_magic_quotes_runtime", MAY_BE_FALSE),
- I0("get_magic_quotes_gpc", MAY_BE_FALSE),
- I0("get_magic_quotes_runtime", MAY_BE_FALSE),
- F0("error_log", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("error_get_last", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("quoted_printable_decode", MAY_BE_STRING),
+ F1("quoted_printable_encode", MAY_BE_STRING),
+ F1("get_current_user", MAY_BE_STRING),
+ F1("get_cfg_var", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("error_get_last", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
FN("call_user_func", UNKNOWN_INFO),
FN("call_user_func_array", UNKNOWN_INFO),
FN("call_user_method", UNKNOWN_INFO),
FN("call_user_method_array", UNKNOWN_INFO),
FN("forward_static_call", UNKNOWN_INFO),
FN("forward_static_call_array", UNKNOWN_INFO),
- F1("serialize", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("serialize", MAY_BE_STRING),
FN("unserialize", UNKNOWN_INFO),
- F0("var_dump", MAY_BE_NULL),
F1("var_export", MAY_BE_NULL | MAY_BE_STRING),
- F0("debug_zval_dump", MAY_BE_NULL),
F1("print_r", MAY_BE_TRUE | MAY_BE_STRING),
- F0("memory_get_usage", MAY_BE_FALSE | MAY_BE_LONG),
- F0("memory_get_peak_usage", MAY_BE_FALSE | MAY_BE_LONG),
F0("register_shutdown_function", MAY_BE_NULL | MAY_BE_FALSE),
- F0("register_tick_function", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("unregister_tick_function", MAY_BE_NULL),
- F1("highlight_file", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("show_source", MAY_BE_FALSE | MAY_BE_STRING),
- F1("highlight_string", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("php_strip_whitespace", MAY_BE_FALSE | MAY_BE_STRING),
- FN("ini_get", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("ini_get_all", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- FN("ini_set", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("ini_alter", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("ini_restore", MAY_BE_NULL),
- I1("get_include_path", MAY_BE_FALSE | MAY_BE_STRING),
- F1("set_include_path", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("restore_include_path", MAY_BE_NULL),
- F0("setcookie", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("setrawcookie", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("header", MAY_BE_NULL),
- F0("header_remove", MAY_BE_NULL),
- F0("headers_sent", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("highlight_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
+ F1("show_source", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("highlight_string", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
+ F1("php_strip_whitespace", MAY_BE_STRING),
+ F1("ini_get_all", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("ini_alter", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("get_include_path", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("set_include_path", MAY_BE_FALSE | MAY_BE_STRING),
F1("headers_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("http_response_code", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("connection_aborted", MAY_BE_LONG),
- F0("connection_status", MAY_BE_LONG),
- F0("ignore_user_abort", MAY_BE_NULL | MAY_BE_LONG),
F1("parse_ini_file", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("parse_ini_string", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#if ZEND_DEBUG
F1("config_get_hash", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
#endif
- F0("is_uploaded_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("move_uploaded_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("gethostbyaddr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gethostbyname", MAY_BE_NULL | MAY_BE_STRING),
- F1("gethostbynamel", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("gethostbyaddr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gethostbyname", MAY_BE_STRING),
+ F1("gethostbynamel", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_GETHOSTNAME
F1("gethostname", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if defined(PHP_WIN32) || HAVE_DNS_SEARCH_FUNC
- F0("dns_check_record", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("checkdnsrr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
# if defined(PHP_WIN32) || HAVE_FULL_DNS_FUNCS
- F0("dns_get_mx", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("getmxrr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("dns_get_record", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
+ F1("dns_get_record", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
# endif
#endif
- F0("intval", MAY_BE_NULL | MAY_BE_LONG),
- F0("floatval", MAY_BE_NULL | MAY_BE_DOUBLE),
- F0("doubleval", MAY_BE_NULL | MAY_BE_DOUBLE),
- FN("strval", MAY_BE_NULL | MAY_BE_STRING),
- F0("boolval", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FN("gettype", MAY_BE_NULL | MAY_BE_STRING),
- F0("settype", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FC("is_null", zend_is_type_info),
- F0("is_resource", MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline with support for closed resources
- FC("is_bool", zend_is_type_info),
- FC("is_long", zend_is_type_info),
- FC("is_float", zend_is_type_info),
- FC("is_int", zend_is_type_info),
- FC("is_integer", zend_is_type_info),
- FC("is_double", zend_is_type_info),
- FC("is_real", zend_is_type_info),
- F0("is_numeric", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FC("is_string", zend_is_type_info),
- FC("is_array", zend_is_type_info),
- F0("is_object", MAY_BE_FALSE | MAY_BE_TRUE), // TODO: inline with support for incomplete class
- F0("is_scalar", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_callable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_countable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_iterable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("pclose", MAY_BE_FALSE | MAY_BE_LONG),
- F1("popen", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("readfile", MAY_BE_FALSE | MAY_BE_LONG),
- F0("rewind", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("rmdir", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("umask", MAY_BE_FALSE | MAY_BE_LONG),
- F0("fclose", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("feof", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("popen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("fgetc", MAY_BE_FALSE | MAY_BE_STRING),
F1("fgets", MAY_BE_FALSE | MAY_BE_STRING),
- F1("fgetss", MAY_BE_FALSE | MAY_BE_STRING),
F1("fread", MAY_BE_FALSE | MAY_BE_STRING),
F1("fopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("fpassthru", MAY_BE_FALSE | MAY_BE_LONG),
- F0("ftruncate", MAY_BE_FALSE | MAY_BE_TRUE),
F1("fstat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
- F0("fseek", MAY_BE_FALSE | MAY_BE_LONG),
- F0("ftell", MAY_BE_FALSE | MAY_BE_LONG),
- F0("fflush", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("fwrite", MAY_BE_FALSE | MAY_BE_LONG),
- F0("fputs", MAY_BE_FALSE | MAY_BE_LONG),
- F0("mkdir", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("rename", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("copy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("tempnam", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("tempnam", MAY_BE_FALSE | MAY_BE_STRING),
F1("tmpfile", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("file_get_contents", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("file_put_contents", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("stream_select", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("stream_context_create", MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("file", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("file_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("stream_context_create", MAY_BE_RESOURCE),
F0("stream_context_set_params", MAY_BE_FALSE | MAY_BE_TRUE),
F1("stream_context_get_params", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
- F0("stream_context_set_option", MAY_BE_FALSE | MAY_BE_TRUE),
FN("stream_context_get_options", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
FN("stream_context_get_default", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("stream_context_set_default", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("stream_filter_prepend", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("stream_filter_append", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("stream_filter_remove", MAY_BE_FALSE | MAY_BE_TRUE),
F1("stream_socket_client", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("stream_socket_server", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("stream_socket_accept", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("stream_socket_get_name", MAY_BE_FALSE | MAY_BE_STRING),
F1("stream_socket_recvfrom", MAY_BE_FALSE | MAY_BE_STRING),
- F0("stream_socket_sendto", MAY_BE_FALSE | MAY_BE_LONG),
- F0("stream_socket_enable_crypto", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG),
-#ifdef HAVE_SHUTDOWN
- F0("stream_socket_shutdown", MAY_BE_FALSE | MAY_BE_TRUE),
-#endif
#if HAVE_SOCKETPAIR
F1("stream_socket_pair", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_RESOURCE),
#endif
- F0("stream_copy_to_stream", MAY_BE_FALSE | MAY_BE_LONG),
F1("stream_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
- F0("stream_supports_lock", MAY_BE_FALSE | MAY_BE_TRUE),
F1("fgetcsv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_NULL | MAY_BE_ARRAY_OF_STRING),
- F0("fputcsv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("flock", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("get_meta_tags", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F0("stream_set_read_buffer", MAY_BE_FALSE | MAY_BE_LONG),
- F0("stream_set_write_buffer", MAY_BE_FALSE | MAY_BE_LONG),
- F0("set_file_buffer", MAY_BE_FALSE | MAY_BE_LONG),
- F0("stream_set_chunk_size", MAY_BE_FALSE | MAY_BE_LONG),
- F0("stream_set_blocking", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("socket_set_blocking", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("stream_get_meta_data", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("get_meta_tags", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
+ F1("stream_get_meta_data", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("stream_get_line", MAY_BE_FALSE | MAY_BE_STRING),
- F0("stream_wrapper_register", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("stream_register_wrapper", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("stream_wrapper_unregister", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("stream_wrapper_restore", MAY_BE_FALSE | MAY_BE_TRUE),
F1("stream_get_wrappers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("stream_get_transports", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("stream_resolve_include_path", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("stream_is_local", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("get_headers", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
-#if HAVE_SYS_TIME_H || defined(PHP_WIN32)
- F0("stream_set_timeout", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("socket_set_timeout", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-#endif
- F1("socket_get_status", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("stream_resolve_include_path", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("get_headers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("socket_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
#if HAVE_REALPATH || defined(ZTS)
- F1("realpath", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
-#endif
-#ifdef HAVE_FNMATCH
- F0("fnmatch", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("realpath", MAY_BE_FALSE | MAY_BE_STRING),
#endif
F1("fsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
FN("pfsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("pack", MAY_BE_FALSE | MAY_BE_STRING),
- F1("unpack", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
+ F1("unpack", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("get_browser", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
- F1("crypt", MAY_BE_NULL | MAY_BE_STRING),
- FN("opendir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("closedir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("chdir", MAY_BE_FALSE | MAY_BE_TRUE),
-#if defined(HAVE_CHROOT) && !defined(ZTS) && ENABLE_CHROOT_FUNC
- F0("chroot", MAY_BE_FALSE | MAY_BE_TRUE),
-#endif
+ F1("crypt", MAY_BE_STRING),
+ FN("opendir", MAY_BE_FALSE | MAY_BE_RESOURCE),
F1("getcwd", MAY_BE_FALSE | MAY_BE_STRING),
- F0("rewinddir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("readdir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("dir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("scandir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("readdir", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("dir", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("scandir", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#ifdef HAVE_GLOB
- F1("glob", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
-#endif
- F0("fileatime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filectime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filegroup", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("fileinode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filemtime", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("fileowner", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("fileperms", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("filesize", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("filetype", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("file_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_writable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_writeable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_readable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_executable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_dir", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("is_link", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("stat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("lstat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("chown", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("chgrp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-#if HAVE_LCHOWN
- F0("lchown", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-#endif
-#if HAVE_LCHOWN
- F0("lchgrp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("glob", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
#endif
- F0("chmod", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-#if HAVE_UTIME
- F0("touch", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-#endif
- F0("clearstatcache", MAY_BE_NULL),
- F0("disk_total_space", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("disk_free_space", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- F0("diskfreespace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_DOUBLE),
- I0("realpath_cache_size", MAY_BE_LONG),
- I1("realpath_cache_get", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F0("mail", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ezmlm_hash", MAY_BE_NULL | MAY_BE_LONG),
+ F1("filetype", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("stat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("lstat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("realpath_cache_get", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
#ifdef HAVE_SYSLOG_H
- F0("openlog", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("syslog", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("syslog", MAY_BE_TRUE),
F0("closelog", MAY_BE_TRUE),
#endif
- F0("lcg_value", MAY_BE_DOUBLE),
- F1("metaphone", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("ob_start", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_flush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_clean", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_end_flush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ob_end_clean", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("ob_get_flush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("ob_get_clean", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("ob_get_length", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("ob_get_level", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("ob_get_status", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- FN("ob_get_contents", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("ob_implicit_flush", MAY_BE_NULL),
- F1("ob_list_handlers", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("ksort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("krsort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("natsort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("natcasesort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("asort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("arsort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("sort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("rsort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("usort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("uasort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("uksort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("shuffle", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("array_walk", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("array_walk_recursive", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("count", MAY_BE_NULL | MAY_BE_LONG),
+ F1("metaphone", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ob_get_flush", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ob_get_clean", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ob_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("ob_list_handlers", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F0("array_walk", MAY_BE_TRUE),
+ F0("array_walk_recursive", MAY_BE_TRUE),
+ F0("arsort", MAY_BE_TRUE),
+ F0("asort", MAY_BE_TRUE),
+ F0("krsort", MAY_BE_TRUE),
+ F0("ksort", MAY_BE_TRUE),
+ F0("shuffle", MAY_BE_TRUE),
+ F0("sort", MAY_BE_TRUE),
+ F0("usort", MAY_BE_TRUE),
+ F0("uasort", MAY_BE_TRUE),
+ F0("uksort", MAY_BE_TRUE),
FN("end", UNKNOWN_INFO),
FN("prev", UNKNOWN_INFO),
FN("next", UNKNOWN_INFO),
FN("reset", UNKNOWN_INFO),
FN("current", UNKNOWN_INFO),
- FN("key", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_STRING),
FN("min", UNKNOWN_INFO),
FN("max", UNKNOWN_INFO),
- F0("in_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FN("array_search", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING),
- F0("extract", MAY_BE_NULL | MAY_BE_LONG),
- F1("compact", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_fill", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
- F1("array_fill_keys", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("compact", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_fill", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
+ F1("array_fill_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
FC("range", zend_range_info),
- F0("array_multisort", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("array_push", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
FN("array_pop", UNKNOWN_INFO),
FN("array_shift", UNKNOWN_INFO),
- F0("array_unshift", MAY_BE_NULL | MAY_BE_LONG),
- F1("array_splice", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_slice", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_merge", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_merge_recursive", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_replace", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_replace_recursive", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_keys", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- FN("array_values", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_count_values", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
- F1("array_column", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_reverse", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_splice", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_slice", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_merge", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_merge_recursive", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_replace", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_replace_recursive", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_keys", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ FN("array_values", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_count_values", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
+ F1("array_column", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_reverse", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_reduce", UNKNOWN_INFO),
- FN("array_pad", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_flip", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("array_change_key_case", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_pad", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_flip", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("array_change_key_case", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("array_rand", UNKNOWN_INFO),
- FN("array_unique", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_key", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_ukey", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_uintersect", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_uintersect_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_intersect_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_uintersect_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_diff", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_key", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_ukey", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_udiff", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_udiff_assoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_diff_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_udiff_uassoc", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F0("array_sum", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE),
- F0("array_product", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_DOUBLE),
- F1("array_filter", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- FN("array_map", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_chunk", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("array_combine", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F0("array_key_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FN("array_key_first", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_STRING),
- FN("array_key_last", MAY_BE_NULL | MAY_BE_LONG | MAY_BE_STRING),
+ FN("array_unique", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_key", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_ukey", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_uintersect", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_uintersect_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_intersect_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_uintersect_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_diff", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_key", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_ukey", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_udiff", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_udiff_assoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_diff_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_udiff_uassoc", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_filter", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ FN("array_map", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_chunk", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("array_combine", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
F1("pos", UNKNOWN_INFO),
- F0("sizeof", MAY_BE_NULL | MAY_BE_LONG),
- F0("key_exists", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("assert", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("assert_options", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_OBJECT | MAY_BE_OBJECT),
- F0("version_compare", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG),
-#if HAVE_FTOK
- F0("ftok", MAY_BE_NULL | MAY_BE_LONG),
-#endif
- F1("str_rot13", MAY_BE_NULL | MAY_BE_STRING),
- I1("stream_get_filters", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("stream_filter_register", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("stream_bucket_make_writeable", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("stream_bucket_prepend", MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("stream_bucket_append", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("str_rot13", MAY_BE_STRING),
+ F1("stream_get_filters", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("stream_bucket_make_writeable", MAY_BE_NULL | MAY_BE_OBJECT),
F1("stream_bucket_new", MAY_BE_FALSE | MAY_BE_OBJECT),
- F0("output_add_rewrite_var", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("output_reset_rewrite_vars", MAY_BE_FALSE),
- I1("sys_get_temp_dir", MAY_BE_STRING),
+ F1("sys_get_temp_dir", MAY_BE_STRING),
/* ext/date */
- F0("strtotime", MAY_BE_FALSE | MAY_BE_LONG),
- F1("date", MAY_BE_FALSE | MAY_BE_STRING),
- F0("idate", MAY_BE_FALSE | MAY_BE_LONG),
- F1("gmdate", MAY_BE_FALSE | MAY_BE_STRING),
- F0("mktime", MAY_BE_FALSE | MAY_BE_LONG),
- F0("gmmktime", MAY_BE_FALSE | MAY_BE_LONG),
- F0("checkdate", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("date", MAY_BE_STRING),
+ F1("gmdate", MAY_BE_STRING),
F1("strftime", MAY_BE_FALSE | MAY_BE_STRING),
F1("gmstrftime", MAY_BE_FALSE | MAY_BE_STRING),
- F0("time", MAY_BE_LONG),
- F1("localtime", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
- F1("getdate", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("localtime", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
+ F1("getdate", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
F1("date_create", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_immutable", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_from_format", MAY_BE_FALSE | MAY_BE_OBJECT),
F1("date_create_immutable_from_format", MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("date_parse", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
- F1("date_parse_from_format", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("date_parse", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("date_parse_from_format", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
F1("date_get_last_errors", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_ARRAY),
- F1("date_format", MAY_BE_FALSE | MAY_BE_STRING),
- FN("date_modify", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_add", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_sub", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("date_format", MAY_BE_STRING),
F1("date_timezone_get", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_timezone_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- F0("date_offset_get", MAY_BE_FALSE | MAY_BE_LONG),
- F1("date_diff", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_time_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_date_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_isodate_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- FN("date_timestamp_set", MAY_BE_FALSE | MAY_BE_OBJECT),
- F0("date_timestamp_get", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("date_diff", MAY_BE_OBJECT),
F1("timezone_open", MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("timezone_name_get", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("timezone_name_get", MAY_BE_STRING),
F1("timezone_name_from_abbr", MAY_BE_FALSE | MAY_BE_STRING),
- F0("timezone_offset_get", MAY_BE_FALSE | MAY_BE_LONG),
F1("timezone_transitions_get", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("timezone_location_get", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING),
F1("timezone_identifiers_list", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("timezone_abbreviations_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("timezone_version_get", MAY_BE_STRING),
F1("date_interval_create_from_date_string", MAY_BE_FALSE | MAY_BE_OBJECT),
- F1("date_interval_format", MAY_BE_FALSE | MAY_BE_STRING),
- F0("date_default_timezone_set", MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("date_interval_format", MAY_BE_STRING),
F1("date_default_timezone_get", MAY_BE_STRING),
F1("date_sunrise", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING),
F1("date_sunset", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_STRING),
- F1("date_sun_info", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG),
+ F1("date_sun_info", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG),
/* ext/preg */
- F0("preg_match", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("preg_match_all", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- FN("preg_replace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
- FN("preg_replace_callback", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
- F1("preg_filter", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
- F1("preg_split", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- FN("preg_quote", MAY_BE_NULL | MAY_BE_STRING),
- F1("preg_grep", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F0("preg_last_error", MAY_BE_NULL | MAY_BE_LONG),
+ FN("preg_replace", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
+ FN("preg_replace_callback", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
+ F1("preg_filter", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING),
+ F1("preg_split", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
+ F1("preg_grep", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
/* ext/mysqli */
F1("mysqli_connect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
F0("mysqli_close", MAY_BE_NULL | MAY_BE_TRUE),
- I1("mysqli_connect_error", MAY_BE_NULL | MAY_BE_STRING),
- I0("mysqli_connect_errno", MAY_BE_LONG),
+ F1("mysqli_connect_error", MAY_BE_NULL | MAY_BE_STRING),
+ F0("mysqli_connect_errno", MAY_BE_LONG),
F1("mysqli_get_client_stats", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("mysqli_error_list", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
F1("mysqli_get_links_stats", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
@@ -981,8 +504,8 @@ static const func_info_t func_infos[] = {
F0("mysqli_field_count", MAY_BE_NULL | MAY_BE_LONG),
F0("mysqli_field_seek", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F0("mysqli_field_tell", MAY_BE_NULL | MAY_BE_LONG),
- I1("mysqli_get_client_info", MAY_BE_STRING),
- I0("mysqli_get_client_version", MAY_BE_LONG),
+ F1("mysqli_get_client_info", MAY_BE_STRING),
+ F0("mysqli_get_client_version", MAY_BE_LONG),
F1("mysqli_get_host_info", MAY_BE_NULL | MAY_BE_STRING),
F0("mysqli_get_proto_info", MAY_BE_NULL | MAY_BE_LONG),
F1("mysqli_get_server_info", MAY_BE_NULL | MAY_BE_STRING),
@@ -1030,254 +553,157 @@ static const func_info_t func_infos[] = {
F1("mysqli_stmt_sqlstate", MAY_BE_NULL | MAY_BE_STRING),
F1("mysqli_store_result", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
F0("mysqli_thread_id", MAY_BE_NULL | MAY_BE_LONG),
- I0("mysqli_thread_safe", MAY_BE_FALSE | MAY_BE_TRUE),
+ F0("mysqli_thread_safe", MAY_BE_FALSE | MAY_BE_TRUE),
F1("mysqli_use_result", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
F0("mysqli_warning_count", MAY_BE_NULL | MAY_BE_LONG),
/* ext/curl */
- F1("curl_init", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("curl_copy_handle", MAY_BE_NULL | MAY_BE_RESOURCE),
- F1("curl_version", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F0("curl_setopt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("curl_setopt_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- FN("curl_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("curl_init", MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("curl_copy_handle", MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("curl_version", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
F1("curl_getinfo", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_LONG | MAY_BE_DOUBLE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- F1("curl_error", MAY_BE_NULL | MAY_BE_STRING),
- F0("curl_errno", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_close", MAY_BE_NULL),
+ F1("curl_error", MAY_BE_STRING),
F1("curl_strerror", MAY_BE_NULL | MAY_BE_STRING),
F1("curl_multi_strerror", MAY_BE_NULL | MAY_BE_STRING),
- F0("curl_reset", MAY_BE_NULL),
- F1("curl_escape", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("curl_unescape", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("curl_pause", MAY_BE_NULL | MAY_BE_LONG),
+ F1("curl_escape", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("curl_unescape", MAY_BE_FALSE | MAY_BE_STRING),
F1("curl_multi_init", MAY_BE_RESOURCE),
- F0("curl_multi_add_handle", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_multi_remove_handle", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_multi_select", MAY_BE_NULL | MAY_BE_LONG),
- F0("curl_multi_exec", MAY_BE_NULL | MAY_BE_LONG),
- FN("curl_multi_getcontent", MAY_BE_NULL | MAY_BE_STRING),
- F1("curl_multi_info_read", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_RESOURCE),
- F0("curl_multi_close", MAY_BE_NULL | MAY_BE_FALSE),
- F0("curl_multi_setopt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("curl_share_init", MAY_BE_RESOURCE),
- F0("curl_share_close", MAY_BE_NULL),
- F0("curl_share_setopt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("curl_multi_info_read", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_RESOURCE),
+ F1("curl_share_init", MAY_BE_RESOURCE),
F1("curl_file_create", MAY_BE_OBJECT),
/* ext/mbstring */
F1("mb_convert_case", MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_strtoupper", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_strtolower", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_language", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("mb_internal_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("mb_http_input", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_http_output", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("mb_detect_order", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("mb_substitute_character", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG | MAY_BE_STRING),
- F0("mb_parse_str", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("mb_output_handler", MAY_BE_NULL | MAY_BE_STRING),
- F1("mb_preferred_mime_name", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("mb_strlen", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("mb_strpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("mb_strrpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("mb_stripos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("mb_strripos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("mb_strstr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_strrchr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_stristr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_strrichr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("mb_substr_count", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("mb_substr", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_strcut", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("mb_strwidth", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F1("mb_strimwidth", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_convert_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- F1("mb_detect_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- I1("mb_list_encodings", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("mb_strtoupper", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_strtolower", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_language", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
+ F1("mb_internal_encoding", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
+ F1("mb_http_input", MAY_BE_FALSE | MAY_BE_STRING| MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("mb_http_output", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
+ F1("mb_detect_order", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("mb_substitute_character", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_LONG | MAY_BE_STRING),
+ F1("mb_output_handler", MAY_BE_STRING),
+ F1("mb_preferred_mime_name", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_strstr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_strrchr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_stristr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_strrichr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_substr", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_strcut", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_strimwidth", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_convert_encoding", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
+ F1("mb_detect_encoding", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_list_encodings", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("mb_encoding_aliases", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("mb_convert_kana", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_encode_mimeheader", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_decode_mimeheader", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_convert_variables", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_encode_numericentity", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mb_decode_numericentity", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("mb_send_mail", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("mb_convert_kana", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_encode_mimeheader", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_decode_mimeheader", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_convert_variables", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_encode_numericentity", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mb_decode_numericentity", MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_get_info", MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
- F0("mb_check_encoding", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("mb_regex_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
- F1("mb_regex_set_options", MAY_BE_FALSE | MAY_BE_STRING),
- F0("mb_ereg", MAY_BE_FALSE | MAY_BE_LONG),
- F0("mb_eregi", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("mb_regex_encoding", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
+ F1("mb_regex_set_options", MAY_BE_STRING),
F1("mb_ereg_replace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_eregi_replace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_ereg_replace_callback", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("mb_split", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("mb_ereg_match", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("mb_ereg_search", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("mb_ereg_search_pos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("mb_ereg_search_regs", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING),
- F0("mb_ereg_search_init", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("mb_ereg_search_pos", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("mb_ereg_search_regs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING),
F1("mb_ereg_search_getregs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING),
- F0("mb_ereg_search_getpos", MAY_BE_LONG),
- F0("mb_ereg_search_setpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-
- F0("mbregex_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("mbereg", MAY_BE_FALSE | MAY_BE_LONG),
- F0("mberegi", MAY_BE_FALSE | MAY_BE_LONG),
- F1("mbereg_replace", MAY_BE_FALSE | MAY_BE_STRING),
- F1("mberegi_replace", MAY_BE_FALSE | MAY_BE_STRING),
- F1("mbsplit", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("mbereg_match", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("mbereg_search", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("mbereg_search_pos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("mbereg_search_regs", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING),
- F0("mbereg_search_init", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("mbereg_search_getregs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_STRING),
- F0("mbereg_search_getpos", MAY_BE_LONG),
- F0("mbereg_search_setpos", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
/* ext/iconv */
- F1("iconv", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("iconv_get_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F0("iconv_set_encoding", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("iconv_strlen", MAY_BE_FALSE | MAY_BE_LONG),
+ F1("iconv", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("iconv_get_encoding", MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("iconv_substr", MAY_BE_FALSE | MAY_BE_STRING),
- F0("iconv_strpos", MAY_BE_FALSE | MAY_BE_LONG),
- F0("iconv_strrpos", MAY_BE_FALSE | MAY_BE_LONG),
F1("iconv_mime_encode", MAY_BE_FALSE | MAY_BE_STRING),
F1("iconv_mime_decode", MAY_BE_FALSE | MAY_BE_STRING),
F1("iconv_mime_decode_headers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
/* ext/json */
- F1("json_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("json_encode", MAY_BE_FALSE | MAY_BE_STRING),
F1("json_decode", MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- I0("json_last_error", MAY_BE_LONG),
- I1("json_last_error_msg", MAY_BE_STRING),
+ F1("json_last_error_msg", MAY_BE_STRING),
/* ext/xml */
- FN("xml_parser_create", MAY_BE_FALSE | MAY_BE_RESOURCE),
- FN("xml_parser_create_ns", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("xml_set_object", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_element_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_character_data_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_processing_instruction_handler",MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_default_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_unparsed_entity_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_notation_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_external_entity_ref_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_start_namespace_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_set_end_namespace_decl_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_parse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_parse_into_struct", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_get_error_code", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F1("xml_error_string", MAY_BE_NULL | MAY_BE_STRING),
- F0("xml_get_current_line_number", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_get_current_column_number", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_get_current_byte_index", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("xml_parser_free", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("xml_parser_set_option", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
F1("xml_parser_get_option", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG | MAY_BE_STRING),
- F1("utf8_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("utf8_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("utf8_encode", MAY_BE_STRING),
+ F1("utf8_decode", MAY_BE_STRING),
/* ext/zlib */
- F0("readgzfile", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("gzrewind", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("gzclose", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("gzeof", MAY_BE_FALSE | MAY_BE_TRUE),
F1("gzgetc", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzgets", MAY_BE_FALSE | MAY_BE_STRING),
- F1("gzgetss", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzread", MAY_BE_FALSE | MAY_BE_STRING),
F1("gzopen", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("gzpassthru", MAY_BE_FALSE | MAY_BE_LONG),
- F0("gzseek", MAY_BE_FALSE | MAY_BE_LONG),
- F0("gztell", MAY_BE_FALSE | MAY_BE_LONG),
- F0("gzwrite", MAY_BE_FALSE | MAY_BE_LONG),
- F0("gzputs", MAY_BE_FALSE | MAY_BE_LONG),
- F1("gzfile", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("gzcompress", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gzuncompress", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gzdeflate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gzinflate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gzencode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gzdecode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("zlib_encode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("zlib_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- I1("zlib_get_coding_type", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gzfile", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
+ F1("gzcompress", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gzuncompress", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gzdeflate", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gzinflate", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gzencode", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gzdecode", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("zlib_encode", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("zlib_decode", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("zlib_get_coding_type", MAY_BE_FALSE | MAY_BE_STRING),
F1("ob_gzhandler", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/hash */
- F1("hash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("hash_equals", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("hash_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("hash_hmac", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("hash", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("hash_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("hash_hmac", MAY_BE_FALSE | MAY_BE_STRING),
F1("hash_hmac_algos", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("hash_hmac_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("hash_hkdf", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("hash_init", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
- F0("hash_update", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("hash_update_stream", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("hash_update_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("hash_final", MAY_BE_NULL | MAY_BE_STRING),
- F1("hash_copy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("hash_hmac_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("hash_hkdf", MAY_BE_STRING),
+ F1("hash_init", MAY_BE_OBJECT),
+ F1("hash_final", MAY_BE_STRING),
+ F1("hash_copy", MAY_BE_OBJECT),
F1("hash_algos", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F1("hash_pbkdf2", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("hash_pbkdf2", MAY_BE_STRING),
F1("mhash_keygen_s2k", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("mhash_get_block_size", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F1("mhash_get_hash_name", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- I0("mhash_count", MAY_BE_LONG),
- F1("mhash", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mhash", MAY_BE_FALSE | MAY_BE_FALSE | MAY_BE_STRING),
/* ext/sodium */
- F0("sodium_memzero", MAY_BE_NULL),
- F0("sodium_increment", MAY_BE_NULL),
- F0("sodium_add", MAY_BE_NULL),
- F0("sodium_memcmp", MAY_BE_NULL | MAY_BE_LONG),
- F1("sodium_crypto_shorthash", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_secretbox", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_secretbox_open", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("sodium_crypto_generichash", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_generichash_init", MAY_BE_NULL | MAY_BE_STRING),
- F0("sodium_crypto_generichash_update", MAY_BE_NULL | MAY_BE_TRUE),
- F1("sodium_crypto_generichash_final", MAY_BE_NULL | MAY_BE_STRING),
+ F1("sodium_crypto_shorthash", MAY_BE_STRING),
+ F1("sodium_crypto_secretbox", MAY_BE_STRING),
+ F1("sodium_crypto_secretbox_open", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sodium_crypto_generichash", MAY_BE_STRING),
+ F1("sodium_crypto_generichash_init", MAY_BE_STRING),
+ F0("sodium_crypto_generichash_update", MAY_BE_TRUE),
+ F1("sodium_crypto_generichash_final", MAY_BE_STRING),
F1("sodium_crypto_box_keypair", MAY_BE_STRING),
- F1("sodium_crypto_box_seed_keypair", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_box_secretkey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_box_publickey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_box", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_box_open", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("sodium_crypto_box_seal", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_box_seal_open", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sodium_crypto_box_seed_keypair", MAY_BE_STRING),
+ F1("sodium_crypto_box_secretkey", MAY_BE_STRING),
+ F1("sodium_crypto_box_publickey", MAY_BE_STRING),
+ F1("sodium_crypto_box", MAY_BE_STRING),
+ F1("sodium_crypto_box_open", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sodium_crypto_box_seal", MAY_BE_STRING),
+ F1("sodium_crypto_box_seal_open", MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_sign_keypair", MAY_BE_STRING),
- F1("sodium_crypto_sign_seed_keypair", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_sign_secretkey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_sign_publickey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_sign", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_sign_open", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("sodium_crypto_sign_detached", MAY_BE_NULL | MAY_BE_STRING),
- F0("sodium_crypto_sign_verify_detached", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("sodium_crypto_stream", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_stream_xor", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_pwhash", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_pwhash_str", MAY_BE_NULL | MAY_BE_STRING),
- F0("sodium_crypto_pwhash_str_verify", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("sodium_crypto_aead_aes256gcm_encrypt", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_aead_aes256gcm_decrypt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("sodium_bin2hex", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_hex2bin", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_scalarmult", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_kx_seed_keypair", MAY_BE_NULL | MAY_BE_STRING),
+ F1("sodium_crypto_sign_seed_keypair", MAY_BE_STRING),
+ F1("sodium_crypto_sign_secretkey", MAY_BE_STRING),
+ F1("sodium_crypto_sign_publickey", MAY_BE_STRING),
+ F1("sodium_crypto_sign", MAY_BE_STRING),
+ F1("sodium_crypto_sign_open", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sodium_crypto_sign_detached", MAY_BE_STRING),
+ F1("sodium_crypto_stream", MAY_BE_STRING),
+ F1("sodium_crypto_stream_xor", MAY_BE_STRING),
+ F1("sodium_crypto_pwhash", MAY_BE_STRING),
+ F1("sodium_crypto_pwhash_str", MAY_BE_STRING),
+ F1("sodium_crypto_aead_aes256gcm_encrypt", MAY_BE_STRING),
+ F1("sodium_crypto_aead_aes256gcm_decrypt", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sodium_bin2hex", MAY_BE_STRING),
+ F1("sodium_hex2bin", MAY_BE_STRING),
+ F1("sodium_crypto_scalarmult", MAY_BE_STRING),
+ F1("sodium_crypto_kx_seed_keypair", MAY_BE_STRING),
F1("sodium_crypto_kx_keypair", MAY_BE_STRING),
F1("sodium_crypto_kx_secretkey", MAY_BE_NULL | MAY_BE_STRING),
F1("sodium_crypto_kx_publickey", MAY_BE_NULL | MAY_BE_STRING),
F1("sodium_crypto_kx_client_session_keys", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("sodium_crypto_kx_server_session_keys", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
F1("sodium_crypto_auth", MAY_BE_NULL | MAY_BE_STRING),
- F0("sodium_crypto_auth_verify", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("sodium_compare", MAY_BE_NULL | MAY_BE_LONG),
F1("sodium_crypto_aead_aes256gcm_keygen", MAY_BE_STRING),
F1("sodium_crypto_auth_keygen", MAY_BE_STRING),
F1("sodium_crypto_generichash_keygen", MAY_BE_STRING),
@@ -1285,53 +711,36 @@ static const func_info_t func_infos[] = {
F1("sodium_crypto_secretbox_keygen", MAY_BE_STRING),
F1("sodium_crypto_shorthash_keygen", MAY_BE_STRING),
F1("sodium_crypto_stream_keygen", MAY_BE_STRING),
- F1("sodium_crypto_kdf_derive_from_key", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_pad", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_unpad", MAY_BE_NULL | MAY_BE_STRING),
+ F1("sodium_crypto_kdf_derive_from_key", MAY_BE_STRING),
+ F1("sodium_pad", MAY_BE_STRING),
+ F1("sodium_unpad", MAY_BE_STRING),
- F1("sodium_crypto_box_keypair_from_secretkey_and_publickey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_box_publickey_from_secretkey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_sign_keypair_from_secretkey_and_publickey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_sign_publickey_from_secretkey", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_pwhash_scryptsalsa208sha256", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_pwhash_scryptsalsa208sha256_str", MAY_BE_NULL | MAY_BE_STRING),
- F0("sodium_crypto_pwhash_scryptsalsa208sha256_str_verify", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("sodium_crypto_aead_aes256gcm_is_available", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("sodium_crypto_sign_ed25519_sk_to_curve25519", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_sign_ed25519_pk_to_curve25519", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_aead_chacha20poly1305_encrypt", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_aead_chacha20poly1305_decrypt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("sodium_crypto_aead_chacha20poly1305_ietf_encrypt", MAY_BE_NULL | MAY_BE_STRING),
- F1("sodium_crypto_aead_chacha20poly1305_ietf_decrypt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("sodium_crypto_aead_xchacha20poly1305_ietf_encrypt", MAY_BE_NULL | MAY_BE_STRING),
+ F1("sodium_crypto_box_keypair_from_secretkey_and_publickey", MAY_BE_STRING),
+ F1("sodium_crypto_box_publickey_from_secretkey", MAY_BE_STRING),
+ F1("sodium_crypto_sign_keypair_from_secretkey_and_publickey", MAY_BE_STRING),
+ F1("sodium_crypto_sign_publickey_from_secretkey", MAY_BE_STRING),
+ F1("sodium_crypto_pwhash_scryptsalsa208sha256", MAY_BE_STRING),
+ F1("sodium_crypto_pwhash_scryptsalsa208sha256_str", MAY_BE_STRING),
+ F1("sodium_crypto_sign_ed25519_sk_to_curve25519", MAY_BE_STRING),
+ F1("sodium_crypto_sign_ed25519_pk_to_curve25519", MAY_BE_STRING),
+ F1("sodium_crypto_aead_chacha20poly1305_encrypt", MAY_BE_STRING),
+ F1("sodium_crypto_aead_chacha20poly1305_decrypt", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sodium_crypto_aead_chacha20poly1305_ietf_encrypt", MAY_BE_STRING),
+ F1("sodium_crypto_aead_chacha20poly1305_ietf_decrypt", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("sodium_crypto_aead_xchacha20poly1305_ietf_encrypt", MAY_BE_STRING),
F1("sodium_crypto_aead_xchacha20poly1305_ietf_decrypt", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_keygen", MAY_BE_STRING),
F1("sodium_crypto_aead_chacha20poly1305_ietf_keygen", MAY_BE_STRING),
F1("sodium_crypto_aead_xchacha20poly1305_ietf_keygen", MAY_BE_STRING),
/* ext/session */
- F0("session_set_cookie_params", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- I1("session_get_cookie_params", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
- F1("session_name", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("session_module_name", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("session_set_save_handler", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("session_save_path", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- FN("session_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("session_regenerate_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("session_create_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("session_cache_limiter", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("session_cache_expire", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- I1("session_encode", MAY_BE_FALSE | MAY_BE_STRING),
- F0("session_decode", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_start", MAY_BE_FALSE | MAY_BE_TRUE),
- I0("session_destroy", MAY_BE_FALSE | MAY_BE_TRUE),
- I0("session_unset", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_gc", MAY_BE_FALSE | MAY_BE_LONG),
- F0("session_write_close", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_abort", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_reset", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("session_status", MAY_BE_NULL | MAY_BE_LONG),
- I0("session_register_shutdown", MAY_BE_NULL),
+ F1("session_get_cookie_params", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("session_name", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("session_module_name", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("session_save_path", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("session_create_id", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("session_cache_limiter", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("session_encode", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/pgsql */
F1("pg_connect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
@@ -1423,201 +832,103 @@ static const func_info_t func_infos[] = {
F1("pg_select", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_STRING),
/* ext/bcmath */
- F1("bcadd", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcsub", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcmul", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcdiv", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcmod", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcpowmod", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("bcpow", MAY_BE_NULL | MAY_BE_STRING),
- F1("bcsqrt", MAY_BE_NULL | MAY_BE_STRING),
- F0("bccomp", MAY_BE_NULL | MAY_BE_LONG),
- F0("bcscale", MAY_BE_NULL | MAY_BE_LONG),
+ F1("bcadd", MAY_BE_STRING),
+ F1("bcsub", MAY_BE_STRING),
+ F1("bcmul", MAY_BE_STRING),
+ F1("bcdiv", MAY_BE_STRING),
+ F1("bcmod", MAY_BE_STRING),
+ F1("bcpowmod", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("bcpow", MAY_BE_STRING),
+ F1("bcsqrt", MAY_BE_STRING),
/* ext/exif */
- F1("exif_tagname", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("exif_read_data", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
- F1("exif_thumbnail", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F0("exif_imagetype", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F1("exif_tagname", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("exif_read_data", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
+ F1("exif_thumbnail", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/filter */
- F0("filter_has_var", MAY_BE_FALSE | MAY_BE_TRUE),
FN("filter_input", UNKNOWN_INFO),
FN("filter_var", UNKNOWN_INFO),
F1("filter_input_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
F1("filter_var_array", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
- I1("filter_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
- F0("filter_id", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
+ F1("filter_list", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
/* ext/gettext */
- F1("textdomain", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("gettext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("_", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("dgettext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("dcgettext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("bindtextdomain", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("textdomain", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("gettext", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("_", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("dgettext", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("dcgettext", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("bindtextdomain", MAY_BE_FALSE | MAY_BE_STRING),
#if HAVE_NGETTEXT
- F1("ngettext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("ngettext", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if HAVE_DNGETTEXT
- F1("dcngettext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("dcngettext", MAY_BE_FALSE | MAY_BE_STRING),
#endif
#if HAVE_BIND_TEXTDOMAIN_CODESET
- F1("bind_textdomain_codeset", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("bind_textdomain_codeset", MAY_BE_FALSE | MAY_BE_STRING),
#endif
- /* ext/ctype */
- F0("ctype_alnum", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_alpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_cntrl", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_digit", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_lower", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_graph", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_print", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_punct", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_space", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_upper", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("ctype_xdigit", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
-
/* ext/fileinfo */
F1("finfo_open", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("finfo_close", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("finfo_set_flags", MAY_BE_FALSE | MAY_BE_TRUE),
- F1("finfo_file", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("finfo_buffer", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
- F1("mime_content_type", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
+ F1("finfo_file", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("finfo_buffer", MAY_BE_FALSE | MAY_BE_STRING),
+ F1("mime_content_type", MAY_BE_FALSE | MAY_BE_STRING),
/* ext/gd */
F1("gd_info", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE),
- F0("imageloadfont", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagesetstyle", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("imagecreatetruecolor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imageistruecolor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagetruecolortopalette", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagepalettetotruecolor", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecolormatch", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesetthickness", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledellipse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledarc", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagealphablending", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesavealpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagelayereffect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecolorallocatealpha", MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolorresolvealpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolorclosestalpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolorexactalpha", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecopyresampled", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("imagecreatetruecolor", MAY_BE_FALSE | MAY_BE_OBJECT),
#ifdef PHP_WIN32
- F1("imagegrabwindow", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imagegrabscreen", MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("imagegrabwindow", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagegrabscreen", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
- F1("imagerotate", MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagesettile", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesetbrush", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("imagecreate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- I0("imagetypes", MAY_BE_LONG),
- F1("imagecreatefromstring", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imagecreatefromgif", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("imagerotate", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagecreate", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagecreatefromstring", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagecreatefromgif", MAY_BE_FALSE | MAY_BE_OBJECT),
#ifdef HAVE_GD_JPG
- F1("imagecreatefromjpeg", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagejpeg", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("jpeg2wbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("imagecreatefromjpeg", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
#ifdef HAVE_GD_PNG
- F1("imagecreatefrompng", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagepng", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("png2wbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("imagecreatefrompng", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
#ifdef HAVE_GD_WEBP
- F1("imagecreatefromwebp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagewebp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("imagecreatefromwebp", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
- F1("imagecreatefromxbm", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("imagecreatefromxbm", MAY_BE_FALSE | MAY_BE_OBJECT),
#if defined(HAVE_GD_XPM)
- F1("imagecreatefromxpm", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("imagecreatefromxpm", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
- F1("imagecreatefromwbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imagecreatefromgd", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imagecreatefromgd2", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imagecreatefromgd2part", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
+ F1("imagecreatefromwbmp", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagecreatefromgd", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagecreatefromgd2", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagecreatefromgd2part", MAY_BE_FALSE | MAY_BE_OBJECT),
#if defined(HAVE_GD_BMP)
- F1("imagecreatefrombmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F0("imagebmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
+ F1("imagecreatefrombmp", MAY_BE_FALSE | MAY_BE_OBJECT),
#endif
- F0("imagexbm", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagegif", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagewbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagegd", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagegd2", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagedestroy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecolorallocate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagepalettecopy", MAY_BE_NULL | MAY_BE_FALSE),
- F0("imagecolorat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolorclosest", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolorclosesthwb", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolordeallocate", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecolorresolve", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolorexact", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
F0("imagecolorset", MAY_BE_NULL | MAY_BE_FALSE),
- F1("imagecolorsforindex", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
- F0("imagegammacorrect", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesetpixel", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageline", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagedashedline", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagerectangle", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledrectangle", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagearc", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageellipse", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilltoborder", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefill", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecolorstotal", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagecolortransparent", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imageinterlace", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagepolygon", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageopenpolygon", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilledpolygon", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefontwidth", MAY_BE_NULL | MAY_BE_LONG),
- F0("imagefontheight", MAY_BE_NULL | MAY_BE_LONG),
- F0("imagechar", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecharup", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagestring", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagestringup", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopymerge", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopymergegray", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagecopyresized", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagesx", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagesy", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_LONG),
- F0("imagesetclip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("imagegetclip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("imageftbbox", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("imagefttext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("imagettfbbox", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F1("imagettftext", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
- F0("image2wbmp", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imagefilter", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageconvolution", MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageflip", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F0("imageantialias", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("imagecrop", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imagecropauto", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imagescale", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imageaffine", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_RESOURCE),
- F1("imageaffinematrixget", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
- F1("imageaffinematrixconcat", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
- F0("imagesetinterpolation", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE),
- F1("imageresolution", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("imagecolorsforindex", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
+ F1("imagegetclip", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("imageftbbox", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("imagefttext", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("imagettfbbox", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("imagettftext", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
+ F1("imagecrop", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagecropauto", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imagescale", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imageaffine", MAY_BE_FALSE | MAY_BE_OBJECT),
+ F1("imageaffinematrixget", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
+ F1("imageaffinematrixconcat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_DOUBLE),
+ F1("imageresolution", MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG),
/* ext/spl */
F1("class_implements", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("class_parents", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
F1("class_uses", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F0("iterator_apply", MAY_BE_NULL | MAY_BE_LONG),
- F0("iterator_count", MAY_BE_FALSE | MAY_BE_LONG),
- F1("iterator_to_array", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
- F1("spl_classes", MAY_BE_NULL | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
- F1("spl_object_hash", MAY_BE_NULL | MAY_BE_STRING),
- F0("spl_object_id", MAY_BE_NULL | MAY_BE_LONG),
+ F1("iterator_to_array", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_OF_ANY),
+ F1("spl_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_STRING),
+ F1("spl_object_hash", MAY_BE_STRING),
};
@@ -1631,30 +942,33 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa
if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
zval *zv;
- func_info_t *info;
+ zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2));
- if (!call_info->callee_func->common.scope && (zv = zend_hash_find_ex(&func_info, Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2, ssa->rt_constants)), 1))) {
- info = Z_PTR_P(zv);
+ if (!call_info->callee_func->common.scope
+ && (zv = zend_hash_find_ex(&func_info, lcname, 1))) {
+ func_info_t *info = Z_PTR_P(zv);
if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
ret = MAY_BE_NULL;
} else if (info->info_func) {
ret = info->info_func(call_info, ssa);
- } else if (/*callee_func->common.arg_info && */
- callee_func->common.num_args == 0 &&
- callee_func->common.required_num_args == 0 &&
- !(callee_func->common.fn_flags & ZEND_ACC_VARIADIC)) {
- if (call_info->num_args == 0) {
- ret = info->info;
- } else {
- ret = FUNC_MAY_WARN | MAY_BE_NULL;
- }
} else {
ret = info->info;
}
-#if 0
+ return ret;
+ }
+
+ if (callee_func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ zend_class_entry *ce; // TODO: Use the CE.
+ ret = zend_fetch_arg_info_type(NULL, callee_func->common.arg_info - 1, &ce);
} else {
+#if 0
fprintf(stderr, "Unknown internal function '%s'\n", func->common.function_name);
#endif
+ ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
+ | MAY_BE_RC1 | MAY_BE_RCN;
+ }
+ if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ ret |= MAY_BE_REF;
}
} else {
// FIXME: the order of functions matters!!!
@@ -1662,18 +976,14 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa
if (info) {
ret = info->return_info.type;
}
- }
- if (!ret) {
- ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
- if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
- ret |= FUNC_MAY_WARN;
- }
- if (callee_func->common.fn_flags & ZEND_ACC_GENERATOR) {
- ret = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT;
- } else if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
- ret |= MAY_BE_REF;
- } else {
- ret |= MAY_BE_RC1 | MAY_BE_RCN;
+ if (!ret) {
+ ret = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF
+ | MAY_BE_RC1 | MAY_BE_RCN;
+ /* For generators RETURN_REFERENCE refers to the yielded values. */
+ if ((callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
+ && !(callee_func->common.fn_flags & ZEND_ACC_GENERATOR)) {
+ ret |= MAY_BE_REF;
+ }
}
}
return ret;
diff --git a/ext/opcache/Optimizer/zend_func_info.h b/ext/opcache/Optimizer/zend_func_info.h
index 7eeb363da5..0f4fcea092 100644
--- a/ext/opcache/Optimizer/zend_func_info.h
+++ b/ext/opcache/Optimizer/zend_func_info.h
@@ -34,11 +34,6 @@
#define ZEND_FUNC_HAS_EXTENDED_FCALL (1<<10)
#define ZEND_FUNC_HAS_EXTENDED_STMT (1<<11)
-/* The following flags are valid only for return values of internal functions
- * returned by zend_get_func_info()
- */
-#define FUNC_MAY_WARN (1<<30)
-
typedef struct _zend_func_info zend_func_info;
typedef struct _zend_call_info zend_call_info;
diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c
index 7accf73a5d..90273e2ffd 100644
--- a/ext/opcache/Optimizer/zend_inference.c
+++ b/ext/opcache/Optimizer/zend_inference.c
@@ -1030,23 +1030,7 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
}
}
} else if (ssa->ops[line].result_def == var) {
- if (opline->extended_value == IS_NULL) {
- tmp->min = 0;
- tmp->max = 0;
- return 1;
- } else if (opline->extended_value == _IS_BOOL) {
- if (OP1_HAS_RANGE()) {
- op1_min = OP1_MIN_RANGE();
- op1_max = OP1_MAX_RANGE();
- tmp->min = (op1_min > 0 || op1_max < 0);
- tmp->max = (op1_min != 0 || op1_max != 0);
- return 1;
- } else {
- tmp->min = 0;
- tmp->max = 1;
- return 1;
- }
- } else if (opline->extended_value == IS_LONG) {
+ if (opline->extended_value == IS_LONG) {
if (OP1_HAS_RANGE()) {
tmp->min = OP1_MIN_RANGE();
tmp->max = OP1_MAX_RANGE();
@@ -1419,13 +1403,15 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int
return 1;
} else if (op_array->arg_info &&
opline->op1.num <= op_array->num_args) {
- if (ZEND_TYPE_CODE(op_array->arg_info[opline->op1.num-1].type) == IS_LONG) {
+ zend_type type = op_array->arg_info[opline->op1.num-1].type;
+ uint32_t mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(type);
+ if (mask == MAY_BE_LONG) {
tmp->underflow = 0;
tmp->min = ZEND_LONG_MIN;
tmp->max = ZEND_LONG_MAX;
tmp->overflow = 0;
return 1;
- } else if (ZEND_TYPE_CODE(op_array->arg_info[opline->op1.num-1].type) == _IS_BOOL) {
+ } else if (mask == MAY_BE_BOOL) {
tmp->underflow = 0;
tmp->min = 0;
tmp->max = 1;
@@ -1833,9 +1819,7 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{
/* }}} */
static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) {
- if (alias == PHP_ERRORMSG_ALIAS) {
- return MAY_BE_STRING | MAY_BE_RC1 | MAY_BE_RCN;
- } else if (alias == HTTP_RESPONSE_HEADER_ALIAS) {
+ if (alias == HTTP_RESPONSE_HEADER_ALIAS) {
return MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_RC1 | MAY_BE_RCN;
} else {
return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
@@ -2063,16 +2047,10 @@ uint32_t zend_array_element_type(uint32_t t1, int write, int insert)
}
if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
tmp |= MAY_BE_NULL;
- if (t1 & MAY_BE_ERROR) {
- if (write) {
- tmp |= MAY_BE_ERROR;
- }
- }
}
if (t1 & (MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_NULL;
- if (write) {
- tmp |= MAY_BE_ERROR;
+ if (!write) {
+ tmp |= MAY_BE_NULL;
}
}
return tmp;
@@ -2234,42 +2212,43 @@ static inline zend_class_entry *get_class_entry(const zend_script *script, zend_
return NULL;
}
-static uint32_t zend_convert_type_code_to_may_be(zend_uchar type_code) {
- switch (type_code) {
- case IS_VOID:
- return MAY_BE_NULL;
- case IS_CALLABLE:
- return MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
- case IS_ITERABLE:
- return MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
- case IS_ARRAY:
- return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
- case _IS_BOOL:
- return MAY_BE_TRUE|MAY_BE_FALSE;
- default:
- ZEND_ASSERT(type_code < IS_REFERENCE);
- return 1 << type_code;
+static uint32_t zend_convert_type_declaration_mask(uint32_t type_mask) {
+ uint32_t result_mask = type_mask & MAY_BE_ANY;
+ if (type_mask & MAY_BE_VOID) {
+ result_mask |= MAY_BE_NULL;
+ }
+ if (type_mask & MAY_BE_CALLABLE) {
+ result_mask |= MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
}
+ if (type_mask & MAY_BE_ITERABLE) {
+ result_mask |= MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ }
+ if (type_mask & MAY_BE_ARRAY) {
+ result_mask |= MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ }
+ return result_mask;
}
-static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce)
+uint32_t zend_fetch_arg_info_type(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce)
{
- uint32_t tmp = 0;
+ uint32_t tmp;
+ if (!ZEND_TYPE_IS_SET(arg_info->type)) {
+ return MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_RC1|MAY_BE_RCN;
+ }
+ tmp = zend_convert_type_declaration_mask(ZEND_TYPE_PURE_MASK(arg_info->type));
*pce = NULL;
- if (ZEND_TYPE_IS_CLASS(arg_info->type)) {
- // class type hinting...
- zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(arg_info->type));
+ if (ZEND_TYPE_HAS_CLASS(arg_info->type)) {
tmp |= MAY_BE_OBJECT;
- *pce = get_class_entry(script, lcname);
- zend_string_release_ex(lcname, 0);
- } else if (ZEND_TYPE_IS_CODE(arg_info->type)) {
- tmp |= zend_convert_type_code_to_may_be(ZEND_TYPE_CODE(arg_info->type));
- } else {
- tmp |= MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ /* As we only have space to store one CE, we use a plain object type for class unions. */
+ if (ZEND_TYPE_HAS_NAME(arg_info->type)) {
+ zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(arg_info->type));
+ *pce = get_class_entry(script, lcname);
+ zend_string_release_ex(lcname, 0);
+ }
}
- if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
- tmp |= MAY_BE_NULL;
+ if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+ tmp |= MAY_BE_RC1 | MAY_BE_RCN;
}
return tmp;
}
@@ -2314,7 +2293,7 @@ static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, z
}
if (ce) {
prop_info = lookup_prop_info(ce,
- Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)),
+ Z_STR_P(CRT_CONSTANT(opline->op2)),
op_array->scope);
if (prop_info && (prop_info->flags & ZEND_ACC_STATIC)) {
prop_info = NULL;
@@ -2345,12 +2324,12 @@ static zend_property_info *zend_fetch_static_prop_info(const zend_script *script
break;
}
} else if (opline->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op2);
ce = get_class_entry(script, Z_STR_P(zv + 1));
}
if (ce) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op1);
prop_info = lookup_prop_info(ce, Z_STR_P(zv), op_array->scope);
if (prop_info && !(prop_info->flags & ZEND_ACC_STATIC)) {
prop_info = NULL;
@@ -2362,33 +2341,29 @@ static zend_property_info *zend_fetch_static_prop_info(const zend_script *script
static uint32_t zend_fetch_prop_type(const zend_script *script, zend_property_info *prop_info, zend_class_entry **pce)
{
+ if (pce) {
+ *pce = NULL;
+ }
if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) {
- uint32_t type = ZEND_TYPE_IS_CLASS(prop_info->type)
- ? MAY_BE_OBJECT
- : zend_convert_type_code_to_may_be(ZEND_TYPE_CODE(prop_info->type));
+ uint32_t type = zend_convert_type_declaration_mask(ZEND_TYPE_PURE_MASK(prop_info->type));
- if (ZEND_TYPE_ALLOW_NULL(prop_info->type)) {
- type |= MAY_BE_NULL;
- }
if (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
type |= MAY_BE_RC1 | MAY_BE_RCN;
}
- if (pce) {
- if (ZEND_TYPE_IS_CE(prop_info->type)) {
- *pce = ZEND_TYPE_CE(prop_info->type);
- } else if (ZEND_TYPE_IS_NAME(prop_info->type)) {
- zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(prop_info->type));
- *pce = get_class_entry(script, lcname);
- zend_string_release(lcname);
- } else {
- *pce = NULL;
+ if (ZEND_TYPE_HAS_CLASS(prop_info->type)) {
+ type |= MAY_BE_OBJECT;
+ if (pce) {
+ if (ZEND_TYPE_HAS_CE(prop_info->type)) {
+ *pce = ZEND_TYPE_CE(prop_info->type);
+ } else if (ZEND_TYPE_HAS_NAME(prop_info->type)) {
+ zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(prop_info->type));
+ *pce = get_class_entry(script, lcname);
+ zend_string_release(lcname);
+ }
}
}
return type;
}
- if (pce) {
- *pce = NULL;
- }
return MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN;
}
@@ -2419,8 +2394,8 @@ static int zend_update_type_info(const zend_op_array *op_array,
/* If one of the operands cannot have any type, this means the operand derives from
* unreachable code. Propagate the empty result early, so that that the following
* code may assume that operands have at least one type. */
- if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS|MAY_BE_ERROR))
- || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS|MAY_BE_ERROR))) {
+ if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))
+ || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))) {
tmp = 0;
if (ssa_ops[i].result_def >= 0) {
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
@@ -2489,14 +2464,8 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
case ZEND_ASSERT_CHECK:
case ZEND_IN_ARRAY:
- UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_ops[i].result_def);
- break;
case ZEND_ARRAY_KEY_EXISTS:
- tmp = MAY_BE_FALSE|MAY_BE_TRUE;
- if (t2 & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_ARRAY|MAY_BE_OBJECT))) {
- tmp |= MAY_BE_NULL;
- }
- UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
+ UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_ops[i].result_def);
break;
case ZEND_CAST:
if (ssa_ops[i].op1_def >= 0) {
@@ -2514,24 +2483,19 @@ static int zend_update_type_info(const zend_op_array *op_array,
UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def);
}
- tmp = 0;
- if (opline->extended_value == _IS_BOOL) {
- tmp |= MAY_BE_TRUE|MAY_BE_FALSE;
- } else {
- tmp |= 1 << opline->extended_value;
- if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- if ((tmp & MAY_BE_ANY) == (t1 & MAY_BE_ANY)) {
- tmp |= (t1 & MAY_BE_RC1) | MAY_BE_RCN;
- } else if ((opline->extended_value == IS_ARRAY ||
- opline->extended_value == IS_OBJECT) &&
- (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT))) {
- tmp |= MAY_BE_RC1 | MAY_BE_RCN;
- } else if (opline->extended_value == IS_STRING &&
- (t1 & (MAY_BE_STRING|MAY_BE_OBJECT))) {
+ tmp = 1 << opline->extended_value;
+ if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+ if ((tmp & MAY_BE_ANY) == (t1 & MAY_BE_ANY)) {
+ tmp |= (t1 & MAY_BE_RC1) | MAY_BE_RCN;
+ } else if ((opline->extended_value == IS_ARRAY ||
+ opline->extended_value == IS_OBJECT) &&
+ (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT))) {
tmp |= MAY_BE_RC1 | MAY_BE_RCN;
- } else {
- tmp |= MAY_BE_RC1;
- }
+ } else if (opline->extended_value == IS_STRING &&
+ (t1 & (MAY_BE_STRING|MAY_BE_OBJECT))) {
+ tmp |= MAY_BE_RC1 | MAY_BE_RCN;
+ } else {
+ tmp |= MAY_BE_RC1;
}
}
if (opline->extended_value == IS_ARRAY) {
@@ -2711,9 +2675,6 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp |= MAY_BE_LONG;
}
} else {
- if (t1 & MAY_BE_ERROR) {
- tmp |= MAY_BE_NULL;
- }
if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
if (opline->opcode == ZEND_PRE_INC) {
tmp |= MAY_BE_LONG;
@@ -2746,7 +2707,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) {
tmp |= MAY_BE_RC1|MAY_BE_RCN;
}
- tmp |= t1 & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_REF|MAY_BE_RCN);
+ tmp |= t1 & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RCN);
if (t1 & MAY_BE_UNDEF) {
tmp |= MAY_BE_NULL;
}
@@ -2773,9 +2734,6 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp |= MAY_BE_LONG;
}
} else {
- if (t1 & MAY_BE_ERROR) {
- tmp |= MAY_BE_NULL;
- }
if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
if (opline->opcode == ZEND_POST_INC) {
tmp |= MAY_BE_LONG;
@@ -2953,7 +2911,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if (opline->op2_type == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION) {
tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
} else {
- tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_RC1|MAY_BE_RCN);
+ tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
}
if (t2 & MAY_BE_UNDEF) {
tmp |= MAY_BE_NULL;
@@ -2981,7 +2939,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION)) {
tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF;
} else {
- tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_RC1|MAY_BE_RCN);
+ tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN);
}
if (t2 & MAY_BE_UNDEF) {
tmp |= MAY_BE_NULL;
@@ -3109,16 +3067,9 @@ static int zend_update_type_info(const zend_op_array *op_array,
ce = NULL;
if (arg_info) {
- tmp = zend_fetch_arg_info(script, arg_info, &ce);
- if (opline->opcode == ZEND_RECV_INIT &&
- Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) {
- /* The constant may resolve to NULL */
- tmp |= MAY_BE_NULL;
- }
- if (arg_info->pass_by_reference) {
+ tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
+ if (ZEND_ARG_SEND_MODE(arg_info)) {
tmp |= MAY_BE_REF;
- } else if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_RC1|MAY_BE_RCN;
}
} else {
tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
@@ -3156,7 +3107,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
}
case ZEND_DECLARE_ANON_CLASS:
UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_ops[i].result_def);
- if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)))) != NULL) {
+ if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT(opline->op1)))) != NULL) {
UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def);
}
break;
@@ -3184,7 +3135,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
break;
}
} else if (opline->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op2);
if (Z_TYPE_P(zv) == IS_STRING) {
ce = get_class_entry(script, Z_STR_P(zv+1));
UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def);
@@ -3198,7 +3149,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_NEW:
tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT;
if (opline->op1_type == IS_CONST &&
- (ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants)+1))) != NULL) {
+ (ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1))) != NULL) {
UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def);
} else if ((t1 & MAY_BE_CLASS) && ssa_ops[i].op1_use >= 0 && ssa_var_info[ssa_ops[i].op1_use].ce) {
UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_ops[i].op1_use].ce, ssa_var_info[ssa_ops[i].op1_use].is_instanceof, ssa_ops[i].result_def);
@@ -3320,7 +3271,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
break;
case ZEND_FE_FETCH_R:
case ZEND_FE_FETCH_RW:
- tmp = t2;
+ tmp = t2 & MAY_BE_REF;
if (t1 & MAY_BE_OBJECT) {
if (opline->opcode == ZEND_FE_FETCH_RW) {
tmp |= MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
@@ -3369,6 +3320,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_FETCH_LIST_R:
case ZEND_FETCH_LIST_W:
if (ssa_ops[i].op1_def >= 0) {
+ uint32_t key_type = 0;
tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN);
if (opline->opcode == ZEND_FETCH_DIM_W ||
opline->opcode == ZEND_FETCH_DIM_RW ||
@@ -3390,20 +3342,20 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN);
}
if (opline->op2_type == IS_UNUSED) {
- tmp |= MAY_BE_ARRAY_KEY_LONG;
+ key_type |= MAY_BE_ARRAY_KEY_LONG;
} else {
if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
- tmp |= MAY_BE_ARRAY_KEY_LONG;
+ key_type |= MAY_BE_ARRAY_KEY_LONG;
}
if (t2 & MAY_BE_STRING) {
- tmp |= MAY_BE_ARRAY_KEY_STRING;
+ key_type |= MAY_BE_ARRAY_KEY_STRING;
if (opline->op2_type != IS_CONST) {
// FIXME: numeric string
- tmp |= MAY_BE_ARRAY_KEY_LONG;
+ key_type |= MAY_BE_ARRAY_KEY_LONG;
}
}
if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
- tmp |= MAY_BE_ARRAY_KEY_STRING;
+ key_type |= MAY_BE_ARRAY_KEY_STRING;
}
}
} else if (opline->opcode == ZEND_FETCH_DIM_UNSET) {
@@ -3427,19 +3379,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_FETCH_LIST_W:
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_DIM_OP:
- tmp |= MAY_BE_ARRAY | MAY_BE_ARRAY_OF_ARRAY;
- break;
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_ASSIGN_OBJ:
- case ZEND_ASSIGN_OBJ_OP:
- case ZEND_ASSIGN_OBJ_REF:
- case ZEND_PRE_INC_OBJ:
- case ZEND_PRE_DEC_OBJ:
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
- tmp |= MAY_BE_ARRAY_OF_OBJECT;
+ tmp |= key_type | MAY_BE_ARRAY | MAY_BE_ARRAY_OF_ARRAY;
break;
case ZEND_SEND_VAR_EX:
case ZEND_SEND_FUNC_ARG:
@@ -3454,7 +3394,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_VERIFY_RETURN_TYPE:
case ZEND_MAKE_REF:
case ZEND_FE_RESET_RW:
- tmp |= MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
+ tmp |= key_type | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
break;
case ZEND_PRE_INC:
case ZEND_PRE_DEC:
@@ -3462,11 +3402,24 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_POST_DEC:
if (tmp & MAY_BE_ARRAY_OF_LONG) {
/* may overflow */
- tmp |= MAY_BE_ARRAY_OF_DOUBLE;
+ tmp |= key_type | MAY_BE_ARRAY_OF_DOUBLE;
} else if (!(tmp & (MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_DOUBLE))) {
- tmp |= MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE;
+ tmp |= key_type | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE;
}
break;
+ case ZEND_FETCH_OBJ_W:
+ case ZEND_FETCH_OBJ_RW:
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ case ZEND_ASSIGN_OBJ:
+ case ZEND_ASSIGN_OBJ_OP:
+ case ZEND_ASSIGN_OBJ_REF:
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
+ /* These will result in an error exception, unless the element
+ * is already an object. */
+ break;
case ZEND_SEND_VAR:
/* This can occur if a DIM_FETCH_FUNC_ARG with UNUSED op2 is left
* behind, because it can't be converted to DIM_FETCH_R. */
@@ -3490,18 +3443,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
opline->opcode != ZEND_FETCH_LIST_R ? t1 : ((t1 & ~MAY_BE_STRING) | MAY_BE_NULL),
opline->result_type == IS_VAR,
opline->op2_type == IS_UNUSED);
- if (opline->opcode == ZEND_FETCH_DIM_W ||
- opline->opcode == ZEND_FETCH_DIM_RW ||
- opline->opcode == ZEND_FETCH_DIM_FUNC_ARG ||
- opline->opcode == ZEND_FETCH_LIST_W) {
- if (t1 & (MAY_BE_ERROR|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_ERROR;
- } else if (opline->op2_type == IS_UNUSED) {
- tmp |= MAY_BE_ERROR;
- } else if (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
- tmp |= MAY_BE_ERROR;
- }
- } else if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) {
+ if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) {
tmp |= MAY_BE_NULL;
}
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
@@ -3516,26 +3458,11 @@ static int zend_update_type_info(const zend_op_array *op_array,
case ZEND_FETCH_OBJ_W:
case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_OBJ_FUNC_ARG:
- if (ssa_ops[i].op1_def >= 0) {
- tmp = t1;
- if (opline->opcode == ZEND_FETCH_OBJ_W ||
- opline->opcode == ZEND_FETCH_OBJ_RW ||
- opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
- if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) {
- if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
- tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE);
- tmp |= MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN;
- }
- }
- }
- UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
- COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def);
- }
if (ssa_ops[i].result_def >= 0) {
tmp = zend_fetch_prop_type(script,
zend_fetch_prop_info(op_array, ssa, opline, i), &ce);
if (opline->result_type != IS_TMP_VAR) {
- tmp |= MAY_BE_REF | MAY_BE_ERROR;
+ tmp |= MAY_BE_REF;
}
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
if (ce) {
@@ -3552,7 +3479,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
tmp = zend_fetch_prop_type(script,
zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce);
if (opline->result_type != IS_TMP_VAR) {
- tmp |= MAY_BE_REF | MAY_BE_ERROR;
+ tmp |= MAY_BE_REF;
}
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
if (ce) {
@@ -3574,7 +3501,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
if (!call_info) {
goto unknown_opcode;
}
- tmp = zend_get_func_info(call_info, ssa) & ~FUNC_MAY_WARN;
+ tmp = zend_get_func_info(call_info, ssa);
UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
if (call_info->callee_func->type == ZEND_USER_FUNCTION) {
func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array);
@@ -3622,11 +3549,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
ce = NULL;
} else {
zend_arg_info *ret_info = op_array->arg_info - 1;
-
- tmp = zend_fetch_arg_info(script, ret_info, &ce);
- if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- tmp |= MAY_BE_RC1 | MAY_BE_RCN;
- }
+ tmp = zend_fetch_arg_info_type(script, ret_info, &ce);
}
if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def);
@@ -3893,7 +3816,7 @@ static zend_bool can_convert_to_double(
ZVAL_COPY_VALUE(&orig_op1, value);
ZVAL_DOUBLE(&dval_op1, (double) Z_LVAL_P(value));
} else if (opline->op1_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op1);
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
ZVAL_COPY_VALUE(&orig_op1, zv);
ZVAL_COPY_VALUE(&dval_op1, zv);
@@ -3906,7 +3829,7 @@ static zend_bool can_convert_to_double(
ZVAL_COPY_VALUE(&orig_op2, value);
ZVAL_DOUBLE(&dval_op2, (double) Z_LVAL_P(value));
} else if (opline->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op2);
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_DOUBLE) {
ZVAL_COPY_VALUE(&orig_op2, zv);
ZVAL_COPY_VALUE(&dval_op2, zv);
@@ -3994,7 +3917,7 @@ static int zend_type_narrowing(const zend_op_array *op_array, const zend_script
* doubles instead, in the hope that we'll narrow long|double to double. */
if (opline->opcode == ZEND_ASSIGN && opline->result_type == IS_UNUSED &&
opline->op1_type == IS_CV && opline->op2_type == IS_CONST) {
- zval *value = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants);
+ zval *value = CRT_CONSTANT(opline->op2);
zend_bitset_clear(visited, bitset_len);
if (can_convert_to_double(op_array, ssa, v, value, visited)) {
@@ -4053,11 +3976,9 @@ void zend_init_func_return_info(const zend_op_array *op_array,
zend_arg_info *ret_info = op_array->arg_info - 1;
zend_ssa_range tmp_range = {0, 0, 0, 0};
- ret->type = zend_fetch_arg_info(script, ret_info, &ret->ce);
+ ret->type = zend_fetch_arg_info_type(script, ret_info, &ret->ce);
if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
ret->type |= MAY_BE_REF;
- } else if (ret->type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
- ret->type |= MAY_BE_RC1|MAY_BE_RCN;
}
ret->is_instanceof = (ret->ce) ? 1 : 0;
ret->range = tmp_range;
@@ -4148,7 +4069,7 @@ void zend_func_return_info(const zend_op_array *op_array,
}
if (opline->op1_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op1, info->ssa.rt_constants);
+ zval *zv = CRT_CONSTANT(opline->op1);
if (Z_TYPE_P(zv) == IS_NULL) {
if (tmp_has_range < 0) {
@@ -4370,7 +4291,7 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array)
free_alloca(worklist, use_heap);
}
-int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa)
+int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa)
{
uint32_t t1 = OP1_INFO();
uint32_t t2 = OP2_INFO();
@@ -4617,8 +4538,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
zend_class_entry *ce = var_info->ce;
if (var_info->is_instanceof ||
- !ce || ce->create_object || ce->__get || ce->__set ||
- (ce->ce_flags & ZEND_ACC_INHERITED)) {
+ !ce || ce->create_object || ce->__get || ce->__set || ce->parent) {
return 1;
}
@@ -4627,7 +4547,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
if (opline->op2_type == IS_CONST) {
prop_info = zend_hash_find_ptr(&ce->properties_info,
- Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)));
+ Z_STR_P(CRT_CONSTANT(opline->op2)));
if (prop_info && !(prop_info->flags & ZEND_ACC_PUBLIC)) {
return 1;
}
@@ -4657,7 +4577,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
case ZEND_COUNT:
return (t1 & MAY_BE_ANY) != MAY_BE_ARRAY;
case ZEND_RECV_INIT:
- if (Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) {
+ if (Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_CONSTANT_AST) {
return 1;
}
if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
@@ -4683,10 +4603,6 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
return (t1 & MAY_BE_OBJECT) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
case ZEND_CAST:
switch (opline->extended_value) {
- case IS_NULL:
- return 0;
- case _IS_BOOL:
- return (t1 & MAY_BE_OBJECT);
case IS_LONG:
case IS_DOUBLE:
return (t1 & MAY_BE_OBJECT);
@@ -4695,10 +4611,17 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa
case IS_ARRAY:
return (t1 & MAY_BE_OBJECT);
case IS_OBJECT:
- return (t1 & MAY_BE_ARRAY);
- default:
- return 1;
+ return 0;
+ EMPTY_SWITCH_DEFAULT_CASE()
}
+ case ZEND_ARRAY_KEY_EXISTS:
+ if ((t2 & MAY_BE_ANY) != MAY_BE_ARRAY) {
+ return 1;
+ }
+ if ((t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ return 1;
+ }
+ return 0;
default:
return 1;
}
diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h
index ec98fcbef9..f01f6cc786 100644
--- a/ext/opcache/Optimizer/zend_inference.h
+++ b/ext/opcache/Optimizer/zend_inference.h
@@ -26,11 +26,11 @@
/* Bitmask for type inference (zend_ssa_var_info.type) */
#include "zend_type_info.h"
-#define MAY_BE_IN_REG (1<<25) /* value allocated in CPU register */
+#define MAY_BE_IN_REG (1<<29) /* value allocated in CPU register */
//TODO: remome MAY_BE_RC1, MAY_BE_RCN???
-#define MAY_BE_RC1 (1<<27) /* may be non-reference with refcount == 1 */
-#define MAY_BE_RCN (1<<28) /* may be non-reference with refcount > 1 */
+#define MAY_BE_RC1 (1<<30) /* may be non-reference with refcount == 1 */
+#define MAY_BE_RCN (1u<<31) /* may be non-reference with refcount > 1 */
#define MAY_HAVE_DTOR \
(MAY_BE_OBJECT|MAY_BE_RESOURCE \
@@ -40,7 +40,7 @@
static zend_always_inline zend_bool _ssa_##opN##_has_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
return (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL); \
} else { \
return (opline->opN##_type != IS_UNUSED && \
@@ -56,7 +56,7 @@
static zend_always_inline zend_long _ssa_##opN##_min_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG) { \
return Z_LVAL_P(zv); \
} else if (Z_TYPE_P(zv) == IS_TRUE) { \
@@ -80,7 +80,7 @@
static zend_always_inline zend_long _ssa_##opN##_max_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG) { \
return Z_LVAL_P(zv); \
} else if (Z_TYPE_P(zv) == IS_TRUE) { \
@@ -104,7 +104,7 @@
static zend_always_inline char _ssa_##opN##_range_underflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
@@ -122,7 +122,7 @@
static zend_always_inline char _ssa_##opN##_range_overflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants); \
+ zval *zv = CRT_CONSTANT(opline->opN); \
if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
return 0; \
} \
@@ -199,7 +199,7 @@ static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa
if (ssa->var_info && ssa_var_num >= 0) {
return ssa->var_info[ssa_var_num].type;
} else {
- return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ERROR;
+ return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
}
}
@@ -207,7 +207,7 @@ static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa
static zend_always_inline uint32_t _ssa_##opN##_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
{ \
if (opline->opN##_type == IS_CONST) { \
- return _const_op_type(CRT_CONSTANT_EX(op_array, opline, opline->opN, ssa->rt_constants)); \
+ return _const_op_type(CRT_CONSTANT(opline->opN)); \
} else { \
return get_ssa_var_info(ssa, ssa->ops ? ssa->ops[opline - op_array->opcodes].opN##_use : -1); \
} \
@@ -263,6 +263,8 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array);
int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level);
+uint32_t zend_fetch_arg_info_type(
+ const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce);
void zend_init_func_return_info(const zend_op_array *op_array,
const zend_script *script,
zend_ssa_var_info *ret);
@@ -272,7 +274,7 @@ void zend_func_return_info(const zend_op_array *op_array,
int widening,
zend_ssa_var_info *ret);
-int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa);
+int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa);
END_EXTERN_C()
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 0b4181c051..05221b1587 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -32,10 +32,6 @@
#include "zend_inference.h"
#include "zend_dump.h"
-#ifndef HAVE_DFA_PASS
-# define HAVE_DFA_PASS 1
-#endif
-
static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
{
zval_ptr_dtor_nogc(zvalue);
@@ -343,7 +339,23 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array,
case ZEND_CASE:
case ZEND_FETCH_LIST_R:
case ZEND_COPY_TMP:
+ case ZEND_FETCH_CLASS_NAME:
return 0;
+ case ZEND_ECHO:
+ {
+ zval zv;
+ if (Z_TYPE_P(val) != IS_STRING && zend_optimizer_eval_cast(&zv, IS_STRING, val) == SUCCESS) {
+ zval_ptr_dtor_nogc(val);
+ val = &zv;
+ }
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val);
+ if (Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val) == 0) {
+ MAKE_NOP(opline);
+ }
+ /* TODO: In a subsequent pass, *after* this step and compacting nops, combine consecutive ZEND_ECHOs using the block information from ssa->cfg */
+ /* (e.g. for ext/opcache/tests/opt/sccp_010.phpt) */
+ break;
+ }
case ZEND_CONCAT:
case ZEND_FAST_CONCAT:
case ZEND_FETCH_R:
@@ -656,9 +668,7 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
}
case ZEND_VERIFY_RETURN_TYPE: {
zend_arg_info *ret_info = op_array->arg_info - 1;
- if (ZEND_TYPE_IS_CLASS(ret_info->type)
- || ZEND_TYPE_CODE(ret_info->type) == IS_CALLABLE
- || !ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(ret_info->type), Z_TYPE_P(val))
+ if (!ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(val))
|| (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
return 0;
}
@@ -777,9 +787,9 @@ void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_
}
static zend_class_entry *get_class_entry_from_op1(
- zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants) {
+ zend_script *script, zend_op_array *op_array, zend_op *opline) {
if (opline->op1_type == IS_CONST) {
- zval *op1 = CRT_CONSTANT_EX(op_array, opline, opline->op1, rt_constants);
+ zval *op1 = CRT_CONSTANT(opline->op1);
if (Z_TYPE_P(op1) == IS_STRING) {
zend_string *class_name = Z_STR_P(op1 + 1);
zend_class_entry *ce;
@@ -804,13 +814,12 @@ static zend_class_entry *get_class_entry_from_op1(
}
zend_function *zend_optimizer_get_called_func(
- zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants)
+ zend_script *script, zend_op_array *op_array, zend_op *opline)
{
-#define GET_OP(op) CRT_CONSTANT_EX(op_array, opline, opline->op, rt_constants)
switch (opline->opcode) {
case ZEND_INIT_FCALL:
{
- zend_string *function_name = Z_STR_P(GET_OP(op2));
+ zend_string *function_name = Z_STR_P(CRT_CONSTANT(opline->op2));
zend_function *func;
if (script && (func = zend_hash_find_ptr(&script->function_table, function_name)) != NULL) {
return func;
@@ -827,8 +836,8 @@ zend_function *zend_optimizer_get_called_func(
}
case ZEND_INIT_FCALL_BY_NAME:
case ZEND_INIT_NS_FCALL_BY_NAME:
- if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) {
- zval *function_name = GET_OP(op2) + 1;
+ if (opline->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_STRING) {
+ zval *function_name = CRT_CONSTANT(opline->op2) + 1;
zend_function *func;
if (script && (func = zend_hash_find_ptr(&script->function_table, Z_STR_P(function_name)))) {
return func;
@@ -844,11 +853,11 @@ zend_function *zend_optimizer_get_called_func(
}
break;
case ZEND_INIT_STATIC_METHOD_CALL:
- if (opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING) {
+ if (opline->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_STRING) {
zend_class_entry *ce = get_class_entry_from_op1(
- script, op_array, opline, rt_constants);
+ script, op_array, opline);
if (ce) {
- zend_string *func_name = Z_STR_P(GET_OP(op2) + 1);
+ zend_string *func_name = Z_STR_P(CRT_CONSTANT(opline->op2) + 1);
zend_function *fbc = zend_hash_find_ptr(&ce->function_table, func_name);
if (fbc) {
zend_bool is_public = (fbc->common.fn_flags & ZEND_ACC_PUBLIC) != 0;
@@ -862,9 +871,9 @@ zend_function *zend_optimizer_get_called_func(
break;
case ZEND_INIT_METHOD_CALL:
if (opline->op1_type == IS_UNUSED
- && opline->op2_type == IS_CONST && Z_TYPE_P(GET_OP(op2)) == IS_STRING
+ && opline->op2_type == IS_CONST && Z_TYPE_P(CRT_CONSTANT(opline->op2)) == IS_STRING
&& op_array->scope && !(op_array->scope->ce_flags & ZEND_ACC_TRAIT)) {
- zend_string *method_name = Z_STR_P(GET_OP(op2) + 1);
+ zend_string *method_name = Z_STR_P(CRT_CONSTANT(opline->op2) + 1);
zend_function *fbc = zend_hash_find_ptr(
&op_array->scope->function_table, method_name);
if (fbc) {
@@ -881,7 +890,7 @@ zend_function *zend_optimizer_get_called_func(
case ZEND_NEW:
{
zend_class_entry *ce = get_class_entry_from_op1(
- script, op_array, opline, rt_constants);
+ script, op_array, opline);
if (ce && ce->type == ZEND_USER_CLASS) {
return ce->constructor;
}
@@ -889,7 +898,6 @@ zend_function *zend_optimizer_get_called_func(
}
}
return NULL;
-#undef GET_OP
}
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args) {
@@ -897,14 +905,8 @@ uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args)
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
} else if (zend_string_equals_literal(name, "compact")) {
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
- } else if (zend_string_equals_literal(name, "parse_str") && num_args <= 1) {
- return ZEND_FUNC_INDIRECT_VAR_ACCESS;
- } else if (zend_string_equals_literal(name, "mb_parse_str") && num_args <= 1) {
- return ZEND_FUNC_INDIRECT_VAR_ACCESS;
} else if (zend_string_equals_literal(name, "get_defined_vars")) {
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
- } else if (zend_string_equals_literal(name, "assert")) {
- return ZEND_FUNC_INDIRECT_VAR_ACCESS;
} else if (zend_string_equals_literal(name, "func_num_args")) {
return ZEND_FUNC_VARARG;
} else if (zend_string_equals_literal(name, "func_get_arg")) {
@@ -939,12 +941,13 @@ static void zend_optimize(zend_op_array *op_array,
zend_dump_op_array(op_array, ZEND_DUMP_LIVE_RANGES, "before optimizer", NULL);
}
- /* pass 1
- * - substitute persistent constants (true, false, null, etc)
- * - perform compile-time evaluation of constant binary and unary operations
- * - optimize series of ADD_STRING and/or ADD_CHAR
- * - convert CAST(IS_BOOL,x) into BOOL(x)
- * - pre-evaluate constant function calls
+ /* pass 1 (Simple local optimizations)
+ * - persistent constant substitution (true, false, null, etc)
+ * - constant casting (ADD expects numbers, CONCAT strings, etc)
+ * - constant expression evaluation
+ * - optimize constant conditional JMPs
+ * - pre-evaluate constant function calls
+ * - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM
*/
if (ZEND_OPTIMIZER_PASS_1 & ctx->optimization_level) {
zend_optimizer_pass1(op_array, ctx);
@@ -953,21 +956,8 @@ static void zend_optimize(zend_op_array *op_array,
}
}
- /* pass 2:
- * - convert non-numeric constants to numeric constants in numeric operators
- * - optimize constant conditional JMPs
- */
- if (ZEND_OPTIMIZER_PASS_2 & ctx->optimization_level) {
- zend_optimizer_pass2(op_array);
- if (ctx->debug_level & ZEND_DUMP_AFTER_PASS_2) {
- zend_dump_op_array(op_array, 0, "after pass 2", NULL);
- }
- }
-
- /* pass 3:
- * - optimize $i = $i+expr to $i+=expr
+ /* pass 3: (Jump optimization)
* - optimize series of JMPs
- * - change $i++ to ++$i where possible
*/
if (ZEND_OPTIMIZER_PASS_3 & ctx->optimization_level) {
zend_optimizer_pass3(op_array, ctx);
@@ -996,7 +986,6 @@ static void zend_optimize(zend_op_array *op_array,
}
}
-#if HAVE_DFA_PASS
/* pass 6:
* - DFA optimization
*/
@@ -1007,7 +996,6 @@ static void zend_optimize(zend_op_array *op_array,
zend_dump_op_array(op_array, 0, "after pass 6", NULL);
}
}
-#endif
/* pass 9:
* - Optimize temp variables usage
@@ -1063,6 +1051,8 @@ static void zend_revert_pass_two(zend_op_array *op_array)
{
zend_op *opline, *end;
+ ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) != 0);
+
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
@@ -1072,6 +1062,8 @@ static void zend_revert_pass_two(zend_op_array *op_array)
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline, opline->op2);
}
+ /* reset smart branch flags IS_SMART_BRANCH_JMP[N]Z */
+ opline->result_type &= (IS_TMP_VAR|IS_VAR|IS_CV|IS_CONST);
opline++;
}
#if !ZEND_USE_ABS_CONST_ADDR
@@ -1081,6 +1073,8 @@ static void zend_revert_pass_two(zend_op_array *op_array)
op_array->literals = literals;
}
#endif
+
+ op_array->fn_flags &= ~ZEND_ACC_DONE_PASS_TWO;
}
static void zend_redo_pass_two(zend_op_array *op_array)
@@ -1090,6 +1084,8 @@ static void zend_redo_pass_two(zend_op_array *op_array)
zend_op *old_opcodes = op_array->opcodes;
#endif
+ ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) == 0);
+
#if !ZEND_USE_ABS_CONST_ADDR
if (op_array->last_literal) {
op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
@@ -1116,48 +1112,79 @@ static void zend_redo_pass_two(zend_op_array *op_array)
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
}
+ /* fix jumps to point to new array */
+ switch (opline->opcode) {
#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
- if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
- /* fix jumps to point to new array */
- switch (opline->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
- break;
- case ZEND_JMPZNZ:
- /* relative extended_value don't have to be changed */
- /* break omitted intentionally */
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- case ZEND_FE_RESET_R:
- case ZEND_FE_RESET_RW:
- case ZEND_ASSERT_CHECK:
+ case ZEND_JMP:
+ case ZEND_FAST_CALL:
+ opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
+ break;
+ case ZEND_JMPZNZ:
+ /* relative extended_value don't have to be changed */
+ /* break omitted intentionally */
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_ASSERT_CHECK:
+ opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ break;
+ case ZEND_CATCH:
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
- break;
- case ZEND_CATCH:
- if (!(opline->extended_value & ZEND_LAST_CATCH)) {
- opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ }
+ break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_SWITCH_LONG:
+ case ZEND_SWITCH_STRING:
+ /* relative extended_value don't have to be changed */
+ break;
+#endif
+ case ZEND_IS_IDENTICAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_SMALLER:
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_CASE:
+ case ZEND_ISSET_ISEMPTY_CV:
+ case ZEND_ISSET_ISEMPTY_VAR:
+ case ZEND_ISSET_ISEMPTY_DIM_OBJ:
+ case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+ case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+ case ZEND_INSTANCEOF:
+ case ZEND_TYPE_CHECK:
+ case ZEND_DEFINED:
+ case ZEND_IN_ARRAY:
+ case ZEND_ARRAY_KEY_EXISTS:
+ if (opline->result_type & IS_TMP_VAR) {
+ /* reinitialize result_type of smart branch instructions */
+ if (opline + 1 < end) {
+ if ((opline+1)->opcode == ZEND_JMPZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPZ | IS_TMP_VAR;
+ } else if ((opline+1)->opcode == ZEND_JMPNZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPNZ | IS_TMP_VAR;
+ }
}
- break;
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
- case ZEND_SWITCH_LONG:
- case ZEND_SWITCH_STRING:
- /* relative extended_value don't have to be changed */
- break;
- }
+ }
+ break;
}
-#endif
ZEND_VM_SET_OPCODE_HANDLER(opline);
opline++;
}
+
+ op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
}
-#if HAVE_DFA_PASS
static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
{
zend_op *opline, *end;
@@ -1165,6 +1192,8 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
zend_op *old_opcodes = op_array->opcodes;
#endif
+ ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) == 0);
+
#if !ZEND_USE_ABS_CONST_ADDR
if (op_array->last_literal) {
op_array->opcodes = (zend_op *) erealloc(op_array->opcodes,
@@ -1202,47 +1231,78 @@ static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline, opline->op2);
}
- zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
+ /* fix jumps to point to new array */
+ switch (opline->opcode) {
#if ZEND_USE_ABS_JMP_ADDR && !ZEND_USE_ABS_CONST_ADDR
- if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
- /* fix jumps to point to new array */
- switch (opline->opcode) {
- case ZEND_JMP:
- case ZEND_FAST_CALL:
- opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
- break;
- case ZEND_JMPZNZ:
- /* relative extended_value don't have to be changed */
- /* break omitted intentionally */
- case ZEND_JMPZ:
- case ZEND_JMPNZ:
- case ZEND_JMPZ_EX:
- case ZEND_JMPNZ_EX:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- case ZEND_FE_RESET_R:
- case ZEND_FE_RESET_RW:
- case ZEND_ASSERT_CHECK:
+ case ZEND_JMP:
+ case ZEND_FAST_CALL:
+ opline->op1.jmp_addr = &op_array->opcodes[opline->op1.jmp_addr - old_opcodes];
+ break;
+ case ZEND_JMPZNZ:
+ /* relative extended_value don't have to be changed */
+ /* break omitted intentionally */
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_ASSERT_CHECK:
+ opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ break;
+ case ZEND_CATCH:
+ if (!(opline->extended_value & ZEND_LAST_CATCH)) {
opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
- break;
- case ZEND_CATCH:
- if (!(opline->extended_value & ZEND_LAST_CATCH)) {
- opline->op2.jmp_addr = &op_array->opcodes[opline->op2.jmp_addr - old_opcodes];
+ }
+ break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ case ZEND_SWITCH_LONG:
+ case ZEND_SWITCH_STRING:
+ /* relative extended_value don't have to be changed */
+ break;
+#endif
+ case ZEND_IS_IDENTICAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_SMALLER:
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_CASE:
+ case ZEND_ISSET_ISEMPTY_CV:
+ case ZEND_ISSET_ISEMPTY_VAR:
+ case ZEND_ISSET_ISEMPTY_DIM_OBJ:
+ case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+ case ZEND_ISSET_ISEMPTY_STATIC_PROP:
+ case ZEND_INSTANCEOF:
+ case ZEND_TYPE_CHECK:
+ case ZEND_DEFINED:
+ case ZEND_IN_ARRAY:
+ case ZEND_ARRAY_KEY_EXISTS:
+ if (opline->result_type & IS_TMP_VAR) {
+ /* reinitialize result_type of smart branch instructions */
+ if (opline + 1 < end) {
+ if ((opline+1)->opcode == ZEND_JMPZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPZ | IS_TMP_VAR;
+ } else if ((opline+1)->opcode == ZEND_JMPNZ
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ opline->result_type = IS_SMART_BRANCH_JMPNZ | IS_TMP_VAR;
+ }
}
- break;
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
- case ZEND_SWITCH_LONG:
- case ZEND_SWITCH_STRING:
- /* relative extended_value don't have to be changed */
- break;
- }
+ }
+ break;
}
-#endif
+ zend_vm_set_opcode_handler_ex(opline, op1_info, op2_info, res_info);
opline++;
}
+
+ op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
}
-#endif
static void zend_optimize_op_array(zend_op_array *op_array,
zend_optimizer_ctx *ctx)
@@ -1257,12 +1317,6 @@ static void zend_optimize_op_array(zend_op_array *op_array,
zend_redo_pass_two(op_array);
if (op_array->live_range) {
-#if HAVE_DFA_PASS
- if ((ZEND_OPTIMIZER_PASS_6 & ctx->optimization_level) &&
- (ZEND_OPTIMIZER_PASS_7 & ctx->optimization_level)) {
- return;
- }
-#endif
zend_recalc_live_ranges(op_array, NULL);
}
}
@@ -1287,7 +1341,6 @@ static void zend_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer
}
}
-#if HAVE_DFA_PASS
static void zend_adjust_fcall_stack_size_graph(zend_op_array *op_array)
{
zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
@@ -1315,7 +1368,6 @@ static zend_bool needs_live_range(zend_op_array *op_array, zend_op *def_opline)
}
return 1;
}
-#endif
int zend_optimize_script(zend_script *script, zend_long optimization_level, zend_long debug_level)
{
@@ -1324,9 +1376,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
zend_op_array *op_array;
zend_string *name;
zend_optimizer_ctx ctx;
-#if HAVE_DFA_PASS
zend_call_graph call_graph;
-#endif
ctx.arena = zend_arena_create(64 * 1024);
ctx.script = script;
@@ -1334,38 +1384,20 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
ctx.optimization_level = optimization_level;
ctx.debug_level = debug_level;
- zend_optimize_op_array(&script->main_op_array, &ctx);
-
- ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- zend_optimize_op_array(op_array, &ctx);
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
- if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
- continue;
- }
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
- if (op_array->scope == ce
- && op_array->type == ZEND_USER_FUNCTION
- && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_optimize_op_array(op_array, &ctx);
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
-
-#if HAVE_DFA_PASS
if ((ZEND_OPTIMIZER_PASS_6 & optimization_level) &&
(ZEND_OPTIMIZER_PASS_7 & optimization_level) &&
- zend_build_call_graph(&ctx.arena, script, ZEND_RT_CONSTANTS, &call_graph) == SUCCESS) {
+ zend_build_call_graph(&ctx.arena, script, &call_graph) == SUCCESS) {
/* Optimize using call-graph */
- void *checkpoint = zend_arena_checkpoint(ctx.arena);
int i;
zend_func_info *func_info;
for (i = 0; i < call_graph.op_arrays_count; i++) {
zend_revert_pass_two(call_graph.op_arrays[i]);
+ zend_optimize(call_graph.op_arrays[i], &ctx);
}
+ zend_analyze_call_graph(&ctx.arena, script, &call_graph);
+
for (i = 0; i < call_graph.op_arrays_count; i++) {
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
if (func_info) {
@@ -1444,16 +1476,11 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
for (i = 0; i < call_graph.op_arrays_count; i++) {
ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
}
-
- zend_arena_release(&ctx.arena, checkpoint);
- } else
-#endif
-
- if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
- zend_adjust_fcall_stack_size(&script->main_op_array, &ctx);
+ } else {
+ zend_optimize_op_array(&script->main_op_array, &ctx);
ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
- zend_adjust_fcall_stack_size(op_array, &ctx);
+ zend_optimize_op_array(op_array, &ctx);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
@@ -1464,10 +1491,31 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
if (op_array->scope == ce
&& op_array->type == ZEND_USER_FUNCTION
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- zend_adjust_fcall_stack_size(op_array, &ctx);
+ zend_optimize_op_array(op_array, &ctx);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
+
+ if (ZEND_OPTIMIZER_PASS_12 & optimization_level) {
+ zend_adjust_fcall_stack_size(&script->main_op_array, &ctx);
+
+ ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
+ zend_adjust_fcall_stack_size(op_array, &ctx);
+ } ZEND_HASH_FOREACH_END();
+
+ ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
+ if (ce->refcount > 1 && !zend_string_equals_ci(key, ce->name)) {
+ continue;
+ }
+ ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, name, op_array) {
+ if (op_array->scope == ce
+ && op_array->type == ZEND_USER_FUNCTION
+ && !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
+ zend_adjust_fcall_stack_size(op_array, &ctx);
+ }
+ } ZEND_HASH_FOREACH_END();
+ } ZEND_HASH_FOREACH_END();
+ }
}
ZEND_HASH_FOREACH_STR_KEY_PTR(&script->class_table, key, ce) {
@@ -1497,11 +1545,11 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
if ((debug_level & ZEND_DUMP_AFTER_OPTIMIZER) &&
(ZEND_OPTIMIZER_PASS_7 & optimization_level)) {
zend_dump_op_array(&script->main_op_array,
- ZEND_DUMP_RT_CONSTANTS | ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
+ ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
ZEND_HASH_FOREACH_PTR(&script->function_table, op_array) {
zend_dump_op_array(op_array,
- ZEND_DUMP_RT_CONSTANTS | ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
+ ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(&script->class_table, ce) {
@@ -1510,7 +1558,7 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
&& op_array->type == ZEND_USER_FUNCTION
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_dump_op_array(op_array,
- ZEND_DUMP_RT_CONSTANTS | ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
+ ZEND_DUMP_LIVE_RANGES, "after optimizer", NULL);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h
index 2841d018a5..04528d33e2 100644
--- a/ext/opcache/Optimizer/zend_optimizer.h
+++ b/ext/opcache/Optimizer/zend_optimizer.h
@@ -25,9 +25,9 @@
#include "zend.h"
#include "zend_compile.h"
-#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* CSE, STRING construction */
-#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* Constant conversion and jumps */
-#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* ++, +=, series of jumps */
+#define ZEND_OPTIMIZER_PASS_1 (1<<0) /* Simple local optimizations */
+#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* */
+#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* Jump optimization */
#define ZEND_OPTIMIZER_PASS_4 (1<<3) /* INIT_FCALL_BY_NAME -> DO_FCALL */
#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */
#define ZEND_OPTIMIZER_PASS_6 (1<<5) /* DFA based optimization */
diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h
index df7be73d4f..270a85c89a 100644
--- a/ext/opcache/Optimizer/zend_optimizer_internal.h
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h
@@ -98,7 +98,6 @@ int zend_optimizer_replace_by_const(zend_op_array *op_array,
zend_op *zend_optimizer_get_loop_var_def(const zend_op_array *op_array, zend_op *free_opline);
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx);
-void zend_optimizer_pass2(zend_op_array *op_array);
void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_func_calls(zend_op_array *op_array, zend_optimizer_ctx *ctx);
void zend_optimize_cfg(zend_op_array *op_array, zend_optimizer_ctx *ctx);
@@ -111,7 +110,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
void zend_optimizer_compact_vars(zend_op_array *op_array);
int zend_optimizer_is_disabled_func(const char *name, size_t len);
zend_function *zend_optimizer_get_called_func(
- zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants);
+ zend_script *script, zend_op_array *op_array, zend_op *opline);
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args);
void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline);
void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist);
diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c
index fdc383128b..41a5f10372 100644
--- a/ext/opcache/Optimizer/zend_ssa.c
+++ b/ext/opcache/Optimizer/zend_ssa.c
@@ -54,7 +54,7 @@ static zend_bool needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa
return 0;
}
- /* Make sure that both sucessors of the from block aren't the same. Pi nodes are associated
+ /* Make sure that both successors of the from block aren't the same. Pi nodes are associated
* with predecessor blocks, so we can't distinguish which edge the pi belongs to. */
from_block = &ssa->cfg.blocks[from];
ZEND_ASSERT(from_block->successors_count == 2);
@@ -161,7 +161,7 @@ static inline void pi_not_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
}
static inline uint32_t mask_for_type_check(uint32_t type) {
if (type & MAY_BE_ARRAY) {
- return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ return type | (MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF);
} else {
return type;
}
@@ -192,14 +192,14 @@ static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_f
}
} else if (op->opcode == ZEND_ADD) {
if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
- zv = CRT_CONSTANT_EX(op_array, op, op->op2, (build_flags & ZEND_RT_CONSTANTS));
+ zv = CRT_CONSTANT_EX(op_array, op, op->op2);
if (Z_TYPE_P(zv) == IS_LONG
&& Z_LVAL_P(zv) != ZEND_LONG_MIN) {
*adjustment = -Z_LVAL_P(zv);
return EX_VAR_TO_NUM(op->op1.var);
}
} else if (op->op2_type == IS_CV && op->op1_type == IS_CONST) {
- zv = CRT_CONSTANT_EX(op_array, op, op->op1, (build_flags & ZEND_RT_CONSTANTS));
+ zv = CRT_CONSTANT_EX(op_array, op, op->op1);
if (Z_TYPE_P(zv) == IS_LONG
&& Z_LVAL_P(zv) != ZEND_LONG_MIN) {
*adjustment = -Z_LVAL_P(zv);
@@ -208,7 +208,7 @@ static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_f
}
} else if (op->opcode == ZEND_SUB) {
if (op->op1_type == IS_CV && op->op2_type == IS_CONST) {
- zv = CRT_CONSTANT_EX(op_array, op, op->op2, (build_flags & ZEND_RT_CONSTANTS));
+ zv = CRT_CONSTANT_EX(op_array, op, op->op2);
if (Z_TYPE_P(zv) == IS_LONG) {
*adjustment = Z_LVAL_P(zv);
return EX_VAR_TO_NUM(op->op1.var);
@@ -223,7 +223,7 @@ static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_f
/* e-SSA construction: Pi placement (Pi is actually a Phi with single
* source and constraint).
- * Order of Phis is importent, Pis must be placed before Phis
+ * Order of Phis is important, Pis must be placed before Phis
*/
static void place_essa_pis(
zend_arena **arena, const zend_script *script, const zend_op_array *op_array,
@@ -293,7 +293,7 @@ static void place_essa_pis(
} else if (var1 >= 0 && var2 < 0) {
zend_long add_val2 = 0;
if ((opline-1)->op2_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS));
+ zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2);
if (Z_TYPE_P(zv) == IS_LONG) {
add_val2 = Z_LVAL_P(zv);
@@ -315,9 +315,9 @@ static void place_essa_pis(
} else if (var1 < 0 && var2 >= 0) {
zend_long add_val1 = 0;
if ((opline-1)->op1_type == IS_CONST) {
- zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS));
+ zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1);
if (Z_TYPE_P(zv) == IS_LONG) {
- add_val1 = Z_LVAL_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS)));
+ add_val1 = Z_LVAL_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1));
} else if (Z_TYPE_P(zv) == IS_FALSE) {
add_val1 = 0;
} else if (Z_TYPE_P(zv) == IS_TRUE) {
@@ -427,7 +427,7 @@ static void place_essa_pis(
pi_range_not_equals(pi, -1, 1);
}
}
- } else if (opline->op1_type == IS_VAR &&
+ } else if (opline->op1_type == IS_TMP_VAR &&
((opline-1)->opcode == ZEND_PRE_INC ||
(opline-1)->opcode == ZEND_PRE_DEC) &&
opline->op1.var == (opline-1)->result.var &&
@@ -463,10 +463,10 @@ static void place_essa_pis(
uint32_t type_mask;
if ((opline-1)->op1_type == IS_CV && (opline-1)->op2_type == IS_CONST) {
var = EX_VAR_TO_NUM((opline-1)->op1.var);
- val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS));
+ val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2);
} else if ((opline-1)->op1_type == IS_CONST && (opline-1)->op2_type == IS_CV) {
var = EX_VAR_TO_NUM((opline-1)->op2.var);
- val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1, (build_flags & ZEND_RT_CONSTANTS));
+ val = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1);
} else {
continue;
}
@@ -497,7 +497,7 @@ static void place_essa_pis(
opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV &&
(opline-1)->op2_type == IS_CONST) {
int var = EX_VAR_TO_NUM((opline-1)->op1.var);
- zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2, (build_flags & ZEND_RT_CONSTANTS)) + 1);
+ zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op2) + 1);
zend_class_entry *ce = script ? zend_hash_find_ptr(&script->class_table, lcname) : NULL;
if (!ce) {
ce = zend_hash_find_ptr(CG(class_table), lcname);
@@ -522,7 +522,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
zend_ssa_op *ssa_ops = ssa->ops;
int ssa_vars_count = ssa->vars_count;
int i, j;
- zend_op *opline, *end;
+ zend_op *opline, *end, *next;
int *tmp = NULL;
ALLOCA_FLAG(use_heap = 0);
@@ -552,39 +552,22 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
for (; opline < end; opline++) {
uint32_t k = opline - op_array->opcodes;
if (opline->opcode != ZEND_OP_DATA) {
- zend_op *next = opline + 1;
- if (next < end && next->opcode == ZEND_OP_DATA) {
- if (next->op1_type == IS_CV) {
- ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
- //USE_SSA_VAR(next->op1.var);
- } else if (next->op1_type & (IS_VAR|IS_TMP_VAR)) {
- ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
- //USE_SSA_VAR(op_array->last_var + next->op1.var);
- }
- if (next->op2_type == IS_CV) {
- ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
- //USE_SSA_VAR(next->op2.var);
- } else if (next->op2_type & (IS_VAR|IS_TMP_VAR)) {
- ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
- //USE_SSA_VAR(op_array->last_var + next->op2.var);
- }
- }
+
if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
ssa_ops[k].op1_use = var[EX_VAR_TO_NUM(opline->op1.var)];
//USE_SSA_VAR(op_array->last_var + opline->op1.var)
}
- if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
- if (opline->op2_type == IS_CV) {
- ssa_ops[k].op2_use = var[EX_VAR_TO_NUM(opline->op2.var)];
- }
- ssa_ops[k].op2_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op2.var)
- } else if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
ssa_ops[k].op2_use = var[EX_VAR_TO_NUM(opline->op2.var)];
//USE_SSA_VAR(op_array->last_var + opline->op2.var)
}
+ if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
+ && opline->result_type == IS_CV
+ && opline->opcode != ZEND_RECV) {
+ ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
+ //USE_SSA_VAR(op_array->last_var + opline->result.var)
+ }
+
switch (opline->opcode) {
case ZEND_ASSIGN:
if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op2_type == IS_CV) {
@@ -594,6 +577,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
//NEW_SSA_VAR(opline->op2.var)
}
if (opline->op1_type == IS_CV) {
+add_op1_def:
ssa_ops[k].op1_def = ssa_vars_count;
var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
ssa_vars_count++;
@@ -601,7 +585,6 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
}
break;
case ZEND_ASSIGN_REF:
-//TODO: ???
if (opline->op2_type == IS_CV) {
ssa_ops[k].op2_def = ssa_vars_count;
var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
@@ -609,90 +592,95 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
//NEW_SSA_VAR(opline->op2.var)
}
if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
- }
- break;
- case ZEND_BIND_GLOBAL:
- case ZEND_BIND_STATIC:
- if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
+ goto add_op1_def;
}
break;
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_OBJ:
- if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
+ //USE_SSA_VAR(op_array->last_var + next->op1.var);
+ if (build_flags & ZEND_SSA_RC_INFERENCE && next->op1_type == IS_CV) {
+ ssa_ops[k + 1].op1_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
+ ssa_vars_count++;
+ //NEW_SSA_VAR(next->op1.var)
+ }
}
- if ((build_flags & ZEND_SSA_RC_INFERENCE) && next->op1_type == IS_CV) {
- ssa_ops[k + 1].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(next->op1.var)
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
}
break;
case ZEND_ASSIGN_OBJ_REF:
- if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
+ //USE_SSA_VAR(op_array->last_var + next->op1.var);
+ if (next->op1_type == IS_CV) {
+ ssa_ops[k + 1].op1_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
+ ssa_vars_count++;
+ //NEW_SSA_VAR(next->op1.var)
+ }
}
- /* break missing intentionally */
- case ZEND_ASSIGN_STATIC_PROP_REF:
- if (next->op1_type == IS_CV) {
- ssa_ops[k + 1].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(next->op1.var)
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
}
break;
- case ZEND_PRE_INC_OBJ:
- case ZEND_PRE_DEC_OBJ:
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
- if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
+ case ZEND_ASSIGN_STATIC_PROP:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
+ //USE_SSA_VAR(op_array->last_var + next->op1.var);
+#if 0
+ if ((build_flags & ZEND_SSA_RC_INFERENCE) && next->op1_type == IS_CV) {
+ ssa_ops[k + 1].op1_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
+ ssa_vars_count++;
+ //NEW_SSA_VAR(next->op1.var)
+ }
+#endif
}
break;
- case ZEND_ADD_ARRAY_ELEMENT:
- ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
- case ZEND_INIT_ARRAY:
- if (((build_flags & ZEND_SSA_RC_INFERENCE)
- || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF))
- && opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline+->op1.var)
+ case ZEND_ASSIGN_STATIC_PROP_REF:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
+ //USE_SSA_VAR(op_array->last_var + next->op1.var);
+ if (next->op1_type == IS_CV) {
+ ssa_ops[k + 1].op1_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count;
+ ssa_vars_count++;
+ //NEW_SSA_VAR(next->op1.var)
+ }
}
break;
- case ZEND_ADD_ARRAY_UNPACK:
- ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
+ case ZEND_ASSIGN_STATIC_PROP_OP:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
+ //USE_SSA_VAR(op_array->last_var + next->op1.var);
+ }
break;
- case ZEND_SEND_VAR:
- case ZEND_CAST:
- case ZEND_QM_ASSIGN:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
+ case ZEND_ASSIGN_DIM_OP:
+ case ZEND_ASSIGN_OBJ_OP:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
+ //USE_SSA_VAR(op_array->last_var + next->op1.var);
+ }
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
}
break;
+ case ZEND_ASSIGN_OP:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ case ZEND_BIND_GLOBAL:
+ case ZEND_BIND_STATIC:
case ZEND_SEND_VAR_NO_REF:
case ZEND_SEND_VAR_NO_REF_EX:
case ZEND_SEND_VAR_EX:
@@ -701,96 +689,81 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
case ZEND_SEND_UNPACK:
case ZEND_FE_RESET_RW:
case ZEND_MAKE_REF:
- if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
- }
- break;
- case ZEND_FE_RESET_R:
- if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
- }
- break;
- case ZEND_ASSIGN_OP:
- case ZEND_ASSIGN_DIM_OP:
- case ZEND_ASSIGN_OBJ_OP:
- case ZEND_ASSIGN_STATIC_PROP_OP:
- case ZEND_PRE_INC:
- case ZEND_PRE_DEC:
- case ZEND_POST_INC:
- case ZEND_POST_DEC:
- if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
- }
- break;
- case ZEND_UNSET_CV:
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- break;
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
case ZEND_UNSET_DIM:
case ZEND_UNSET_OBJ:
case ZEND_FETCH_DIM_W:
case ZEND_FETCH_DIM_RW:
case ZEND_FETCH_DIM_FUNC_ARG:
case ZEND_FETCH_DIM_UNSET:
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_FETCH_OBJ_UNSET:
case ZEND_FETCH_LIST_W:
if (opline->op1_type == IS_CV) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
+ goto add_op1_def;
}
break;
- case ZEND_BIND_LEXICAL:
- if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
- ssa_ops[k].op2_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
- ssa_vars_count++;
+ case ZEND_SEND_VAR:
+ case ZEND_CAST:
+ case ZEND_QM_ASSIGN:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_FE_RESET_R:
+ if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_ADD_ARRAY_UNPACK:
+ ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
+ break;
+ case ZEND_ADD_ARRAY_ELEMENT:
+ ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
+ /* break missing intentionally */
+ case ZEND_INIT_ARRAY:
+ if (((build_flags & ZEND_SSA_RC_INFERENCE)
+ || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF))
+ && opline->op1_type == IS_CV) {
+ goto add_op1_def;
}
break;
case ZEND_YIELD:
if (opline->op1_type == IS_CV
&& ((op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)
|| (build_flags & ZEND_SSA_RC_INFERENCE))) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
- ssa_vars_count++;
+ goto add_op1_def;
}
break;
+ case ZEND_UNSET_CV:
+ goto add_op1_def;
case ZEND_VERIFY_RETURN_TYPE:
if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
- ssa_ops[k].op1_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ if (opline->op2_type != IS_CV) {
+ ssa_ops[k].op2_use = -1; /* not used */
+ }
+ ssa_ops[k].op2_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
+ ssa_vars_count++;
+ //NEW_SSA_VAR(opline->op2.var)
+ break;
+ case ZEND_BIND_LEXICAL:
+ if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
+ ssa_ops[k].op2_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(opline->op2.var)] = ssa_vars_count;
ssa_vars_count++;
- //NEW_SSA_VAR(opline->op1.var)
+ //NEW_SSA_VAR(opline->op2.var)
}
break;
default:
break;
}
- if (opline->result_type == IS_CV) {
- if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
- && opline->opcode != ZEND_RECV) {
- ssa_ops[k].result_use = var[EX_VAR_TO_NUM(opline->result.var)];
- }
- ssa_ops[k].result_def = ssa_vars_count;
- var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
- ssa_vars_count++;
- //NEW_SSA_VAR(opline->result.var)
- } else if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
+
+ if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
ssa_ops[k].result_def = ssa_vars_count;
var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
ssa_vars_count++;
@@ -799,6 +772,10 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
}
}
+ zend_ssa_op *fe_fetch_ssa_op = blocks[n].len != 0
+ && ((end-1)->opcode == ZEND_FE_FETCH_R || (end-1)->opcode == ZEND_FE_FETCH_RW)
+ && (end-1)->op2_type == IS_CV
+ ? &ssa_ops[blocks[n].start + blocks[n].len - 1] : NULL;
for (i = 0; i < blocks[n].successors_count; i++) {
int succ = blocks[n].successors[i];
zend_ssa_phi *p;
@@ -828,6 +805,10 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
}
ZEND_ASSERT(j < blocks[succ].predecessors_count);
p->sources[j] = var[p->var];
+ if (fe_fetch_ssa_op && i == 0 && p->sources[j] == fe_fetch_ssa_op->op2_def) {
+ /* On the exit edge of an FE_FETCH, use the pre-modification value instead. */
+ p->sources[j] = fe_fetch_ssa_op->op2_use;
+ }
}
}
for (p = ssa_blocks[succ].phis; p && (p->pi >= 0); p = p->next) {
@@ -881,11 +862,10 @@ int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_
ALLOCA_FLAG(var_use_heap)
if ((blocks_count * (op_array->last_var + op_array->T)) > 4 * 1024 * 1024) {
- /* Don't buld SSA for very big functions */
+ /* Don't build SSA for very big functions */
return FAILURE;
}
- ssa->rt_constants = (build_flags & ZEND_RT_CONSTANTS);
ssa_blocks = zend_arena_calloc(arena, blocks_count, sizeof(zend_ssa_block));
ssa->blocks = ssa_blocks;
@@ -1125,8 +1105,6 @@ int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_
for (i = 0; i < op_array->last_var; i++) {
if ((ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
ssa_vars[i].alias = SYMTABLE_ALIAS;
- } else if (zend_string_equals_literal(op_array->vars[i], "php_errormsg")) {
- ssa_vars[i].alias = PHP_ERRORMSG_ALIAS;
} else if (zend_string_equals_literal(op_array->vars[i], "http_response_header")) {
ssa_vars[i].alias = HTTP_RESPONSE_HEADER_ALIAS;
}
diff --git a/ext/opcache/Optimizer/zend_ssa.h b/ext/opcache/Optimizer/zend_ssa.h
index 0dbbf40efd..5abe44c93d 100644
--- a/ext/opcache/Optimizer/zend_ssa.h
+++ b/ext/opcache/Optimizer/zend_ssa.h
@@ -95,7 +95,6 @@ typedef struct _zend_ssa_op {
typedef enum _zend_ssa_alias_kind {
NO_ALIAS,
SYMTABLE_ALIAS,
- PHP_ERRORMSG_ALIAS,
HTTP_RESPONSE_HEADER_ALIAS
} zend_ssa_alias_kind;
@@ -114,7 +113,7 @@ typedef struct _zend_ssa_var {
int use_chain; /* uses of this value, linked through opN_use_chain */
zend_ssa_phi *phi_use_chain; /* uses of this value in Phi, linked through use_chain */
zend_ssa_phi *sym_use_chain; /* uses of this value in Pi constraints */
- unsigned int no_val : 1; /* value doesn't mater (used as op1 in ZEND_ASSIGN) */
+ unsigned int no_val : 1; /* value doesn't matter (used as op1 in ZEND_ASSIGN) */
unsigned int scc_entry : 1;
unsigned int alias : 2; /* value may be changed indirectly */
unsigned int escape_state : 2;
@@ -132,12 +131,11 @@ typedef struct _zend_ssa_var_info {
typedef struct _zend_ssa {
zend_cfg cfg; /* control flow graph */
- int rt_constants; /* run-time or compile-time */
int vars_count; /* number of SSA variables */
+ int sccs; /* number of SCCs */
zend_ssa_block *blocks; /* array of SSA blocks */
zend_ssa_op *ops; /* array of SSA instructions */
zend_ssa_var *vars; /* use/def chain of SSA variables */
- int sccs; /* number of SCCs */
zend_ssa_var_info *var_info;
} zend_ssa;
@@ -217,10 +215,9 @@ static zend_always_inline zend_bool zend_ssa_is_no_val_use(const zend_op *opline
if (opline->opcode == ZEND_ASSIGN || opline->opcode == ZEND_UNSET_CV) {
return ssa_op->op1_use == var && ssa_op->op2_use != var;
}
- // TODO: Reenable this after changing the SSA structure.
- /*if (opline->opcode == ZEND_FE_FETCH_R) {
+ if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
return ssa_op->op2_use == var && ssa_op->op1_use != var;
- }*/
+ }
if (ssa_op->result_use == var
&& opline->opcode != ZEND_ADD_ARRAY_ELEMENT
&& opline->opcode != ZEND_ADD_ARRAY_UNPACK) {
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index c7d73a999a..938f524ff5 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -31,6 +31,7 @@
#include "zend_accelerator_blacklist.h"
#include "zend_list.h"
#include "zend_execute.h"
+#include "zend_vm.h"
#include "zend_inheritance.h"
#include "zend_exceptions.h"
#include "main/php_main.h"
@@ -47,6 +48,10 @@
#include "ext/standard/md5.h"
#include "ext/hash/php_hash.h"
+#ifdef HAVE_JIT
+# include "jit/zend_jit.h"
+#endif
+
#ifndef ZEND_WIN32
#include <netdb.h>
#endif
@@ -86,19 +91,6 @@ typedef int gid_t;
#include <immintrin.h>
#endif
-#define SHM_PROTECT() \
- do { \
- if (ZCG(accel_directives).protect_memory) { \
- zend_accel_shared_protect(1); \
- } \
- } while (0)
-#define SHM_UNPROTECT() \
- do { \
- if (ZCG(accel_directives).protect_memory) { \
- zend_accel_shared_protect(0); \
- } \
- } while (0)
-
ZEND_EXTENSION();
#ifndef ZTS
@@ -610,10 +602,13 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int
num_args++;
}
for (i = 0 ; i < num_args; i++) {
- if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) {
- zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type);
- arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(new_interned_string(ZEND_TYPE_NAME(arg_info[i].type)), allow_null);
- }
+ zend_type *single_type;
+ ZEND_TYPE_FOREACH(arg_info[i].type, single_type) {
+ if (ZEND_TYPE_HAS_NAME(*single_type)) {
+ ZEND_TYPE_SET_PTR(*single_type,
+ new_interned_string(ZEND_TYPE_NAME(*single_type)));
+ }
+ } ZEND_TYPE_FOREACH_END();
}
}
} ZEND_HASH_FOREACH_END();
@@ -786,6 +781,8 @@ static inline void kill_all_lockers(struct flock *mem_usage_check)
/* Process died before the signal was sent */
success = 1;
zend_accel_error(ACCEL_LOG_WARNING, "Process %d died before SIGKILL was sent", mem_usage_check->l_pid);
+ } else if (errno != 0) {
+ zend_accel_error(ACCEL_LOG_WARNING, "Failed to send SIGKILL to locker %d: %s", mem_usage_check->l_pid, strerror(errno));
}
break;
}
@@ -796,6 +793,8 @@ static inline void kill_all_lockers(struct flock *mem_usage_check)
/* successfully killed locker, process no longer exists */
success = 1;
zend_accel_error(ACCEL_LOG_WARNING, "Killed locker %d", mem_usage_check->l_pid);
+ } else if (errno != 0) {
+ zend_accel_error(ACCEL_LOG_WARNING, "Failed to check locker %d: %s", mem_usage_check->l_pid, strerror(errno));
}
break;
}
@@ -805,7 +804,7 @@ static inline void kill_all_lockers(struct flock *mem_usage_check)
/* errno is not ESRCH or we ran out of tries to kill the locker */
ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
/* cannot kill the locker, bail out with error */
- zend_accel_error(ACCEL_LOG_ERROR, "Cannot kill process %d: %s!", mem_usage_check->l_pid, strerror(errno));
+ zend_accel_error(ACCEL_LOG_ERROR, "Cannot kill process %d!", mem_usage_check->l_pid);
}
mem_usage_check->l_type = F_WRLCK;
@@ -2479,6 +2478,11 @@ int accel_activate(INIT_FUNC_ARGS)
ZCG(pcre_reseted) = 1;
}
+
+#ifdef HAVE_JIT
+ zend_jit_activate();
+#endif
+
if (ZCSG(preload_script)) {
preload_activate();
}
@@ -2486,6 +2490,13 @@ int accel_activate(INIT_FUNC_ARGS)
return SUCCESS;
}
+#ifdef HAVE_JIT
+void accel_deactivate(void)
+{
+ zend_jit_deactivate();
+}
+#endif
+
int accel_post_deactivate(void)
{
if (ZCG(cwd)) {
@@ -2913,12 +2924,46 @@ static int accel_post_startup(void)
}
}
+ /* Initialize zend_func_info_rid */
+ zend_optimizer_startup();
+
/********************************************/
/* End of non-SHM dependent initializations */
/********************************************/
file_cache_only = ZCG(accel_directives).file_cache_only;
if (!file_cache_only) {
- switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
+ size_t shm_size = ZCG(accel_directives).memory_consumption;
+#ifdef HAVE_JIT
+ size_t jit_size = 0;
+ zend_bool reattached = 0;
+
+ if (ZCG(accel_directives).jit &&
+ ZCG(accel_directives).jit_buffer_size) {
+ size_t page_size;
+
+# ifdef _WIN32
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ page_size = system_info.dwPageSize;
+# else
+ page_size = getpagesize();
+# endif
+ if (!page_size || (page_size & (page_size - 1))) {
+ zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can't get page size.");
+ abort();
+ }
+ jit_size = ZCG(accel_directives).jit_buffer_size;
+ jit_size = ZEND_MM_ALIGNED_SIZE_EX(jit_size, page_size);
+ shm_size += jit_size;
+ } else {
+ ZCG(accel_directives).jit = 0;
+ ZCG(accel_directives).jit_buffer_size = 0;
+ }
+
+ switch (zend_shared_alloc_startup(shm_size, jit_size)) {
+#else
+ switch (zend_shared_alloc_startup(shm_size, 0)) {
+#endif
case ALLOC_SUCCESS:
if (zend_accel_init_shm() == FAILURE) {
accel_startup_ok = 0;
@@ -2930,6 +2975,9 @@ static int accel_post_startup(void)
zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
return SUCCESS;
case SUCCESSFULLY_REATTACHED:
+#ifdef HAVE_JIT
+ reattached = 1;
+#endif
zend_shared_alloc_lock();
accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
zend_interned_strings_set_request_storage_handlers(accel_new_interned_string_for_php, accel_init_interned_string_for_php);
@@ -2961,6 +3009,16 @@ static int accel_post_startup(void)
zend_accel_init_auto_globals();
zend_shared_alloc_lock();
+#ifdef HAVE_JIT
+ if (ZCG(accel_directives).jit &&
+ ZCG(accel_directives).jit_buffer_size &&
+ ZSMMG(reserved) &&
+ zend_jit_startup(ZCG(accel_directives).jit, ZSMMG(reserved), jit_size, reattached) == SUCCESS) {
+ ZCG(jit_enabled) = 1;
+ } else {
+ ZCG(jit_enabled) = 0;
+ }
+#endif
zend_shared_alloc_save_state();
zend_shared_alloc_unlock();
@@ -3044,6 +3102,10 @@ void accel_shutdown(void)
zend_ini_entry *ini_entry;
zend_bool _file_cache_only = 0;
+#ifdef HAVE_JIT
+ zend_jit_shutdown();
+#endif
+
zend_optimizer_shutdown();
zend_accel_blacklist_shutdown(&accel_blacklist);
@@ -3068,7 +3130,7 @@ void accel_shutdown(void)
#endif
if (!_file_cache_only) {
- /* Delay SHM dettach */
+ /* Delay SHM detach */
orig_post_shutdown_cb = zend_post_shutdown_cb;
zend_post_shutdown_cb = accel_post_shutdown;
}
@@ -3515,67 +3577,72 @@ static zend_bool preload_try_resolve_constants(zend_class_entry *ce)
return ok;
}
+static zend_class_entry *preload_fetch_resolved_ce(zend_string *name, zend_class_entry *self_ce) {
+ zend_string *lcname = zend_string_tolower(name);
+ zend_class_entry *ce = zend_hash_find_ptr(EG(class_table), lcname);
+ zend_string_release(lcname);
+ if (!ce) {
+ return NULL;
+ }
+ if (ce == self_ce) {
+ /* Ignore the following requirements if this is the class referring to itself */
+ return ce;
+ }
+ if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
+ return NULL;
+ }
+ if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
+ return NULL;
+ }
+ return ce;
+}
+
static zend_bool preload_try_resolve_property_types(zend_class_entry *ce)
{
zend_bool ok = 1;
- zend_property_info *prop;
- zend_class_entry *p;
-
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+ zend_property_info *prop;
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
- zend_string *name, *lcname;
-
- if (!ZEND_TYPE_IS_NAME(prop->type)) {
- continue;
- }
-
- name = ZEND_TYPE_NAME(prop->type);
- lcname = zend_string_tolower(name);
- p = zend_hash_find_ptr(EG(class_table), lcname);
- zend_string_release(lcname);
- if (!p) {
- ok = 0;
- continue;
- }
- if (p != ce) {
- if (!(p->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- ok = 0;
- continue;
- }
- if (!(p->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
+ zend_type *single_type;
+ ZEND_TYPE_FOREACH(prop->type, single_type) {
+ zend_class_entry *p = preload_fetch_resolved_ce(ZEND_TYPE_NAME(*single_type), ce);
+ if (!p) {
ok = 0;
continue;
}
- }
-
- zend_string_release(name);
- prop->type = ZEND_TYPE_ENCODE_CE(p, ZEND_TYPE_ALLOW_NULL(prop->type));
+ ZEND_TYPE_SET_CE(*single_type, p);
+ } ZEND_TYPE_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}
return ok;
}
-static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type type) {
- zend_string *name, *lcname;
- zend_bool known;
- if (!ZEND_TYPE_IS_NAME(type)) {
- return 1;
- }
-
- name = ZEND_TYPE_NAME(type);
+static zend_bool preload_is_class_type_known(zend_class_entry *ce, zend_string *name) {
if (zend_string_equals_literal_ci(name, "self") ||
zend_string_equals_literal_ci(name, "parent") ||
zend_string_equals_ci(name, ce->name)) {
return 1;
}
- lcname = zend_string_tolower(name);
- known = zend_hash_exists(EG(class_table), lcname);
+ zend_string *lcname = zend_string_tolower(name);
+ zend_bool known = zend_hash_exists(EG(class_table), lcname);
zend_string_release(lcname);
return known;
}
+static zend_bool preload_is_type_known(zend_class_entry *ce, zend_type *type) {
+ zend_type *single_type;
+ ZEND_TYPE_FOREACH(*type, single_type) {
+ if (ZEND_TYPE_HAS_NAME(*single_type)) {
+ if (!preload_is_class_type_known(ce, ZEND_TYPE_NAME(*single_type))) {
+ return 0;
+ }
+ }
+ } ZEND_TYPE_FOREACH_END();
+ return 1;
+}
+
static zend_bool preload_is_method_maybe_override(zend_class_entry *ce, zend_string *lcname) {
zend_class_entry *p;
if (ce->trait_aliases || ce->trait_precedences) {
@@ -3620,13 +3687,13 @@ static zend_bool preload_needed_types_known(zend_class_entry *ce) {
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, lcname, fptr) {
uint32_t i;
if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
- if (!preload_is_type_known(ce, fptr->common.arg_info[-1].type) &&
+ if (!preload_is_type_known(ce, &fptr->common.arg_info[-1].type) &&
preload_is_method_maybe_override(ce, lcname)) {
return 0;
}
}
for (i = 0; i < fptr->common.num_args; i++) {
- if (!preload_is_type_known(ce, fptr->common.arg_info[i].type) &&
+ if (!preload_is_type_known(ce, &fptr->common.arg_info[i].type) &&
preload_is_method_maybe_override(ce, lcname)) {
return 0;
}
@@ -3916,11 +3983,14 @@ static void preload_ensure_classes_loadable() {
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_property_info *prop;
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
- if (ZEND_TYPE_IS_NAME(prop->type)) {
- zend_class_entry *ce =
- preload_load_prop_type(prop, ZEND_TYPE_NAME(prop->type));
- prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type));
- }
+ zend_type *single_type;
+ ZEND_TYPE_FOREACH(prop->type, single_type) {
+ if (ZEND_TYPE_HAS_NAME(*single_type)) {
+ zend_class_entry *ce = preload_load_prop_type(
+ prop, ZEND_TYPE_NAME(*single_type));
+ ZEND_TYPE_SET_CE(*single_type, ce);
+ }
+ } ZEND_TYPE_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}
ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
@@ -4080,14 +4150,14 @@ static int preload_optimize(zend_persistent_script *script)
}
ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
- if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) {
+ if (ce->num_traits) {
preload_fix_trait_methods(ce);
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
- if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) {
+ if (ce->num_traits) {
preload_fix_trait_methods(ce);
}
} ZEND_HASH_FOREACH_END();
@@ -4235,7 +4305,7 @@ static void preload_load(void)
if (CG(map_ptr_last) != ZCSG(map_ptr_last)) {
CG(map_ptr_last) = ZCSG(map_ptr_last);
CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096);
- CG(map_ptr_base) = perealloc(CG(map_ptr_base), CG(map_ptr_size) * sizeof(void*), 1);
+ ZEND_MAP_PTR_SET_REAL_BASE(CG(map_ptr_base), perealloc(ZEND_MAP_PTR_REAL_BASE(CG(map_ptr_base)), CG(map_ptr_size) * sizeof(void*), 1));
}
}
@@ -4452,6 +4522,7 @@ static int accel_preload(const char *config)
#else
init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 2);
#endif
+ script->script.main_op_array.fn_flags |= ZEND_ACC_DONE_PASS_TWO;
script->script.main_op_array.last = 1;
script->script.main_op_array.last_literal = 1;
#if ZEND_USE_ABS_CONST_ADDR
@@ -4465,6 +4536,7 @@ static int accel_preload(const char *config)
script->script.main_op_array.opcodes[0].op1_type = IS_CONST;
script->script.main_op_array.opcodes[0].op1.constant = 0;
ZEND_PASS_TWO_UPDATE_CONSTANT(&script->script.main_op_array, script->script.main_op_array.opcodes, script->script.main_op_array.opcodes[0].op1);
+ zend_vm_set_opcode_handler(script->script.main_op_array.opcodes);
script->script.main_op_array.filename = filename;
script->script.filename = zend_string_copy(filename);
@@ -4583,13 +4655,13 @@ static int accel_finish_startup(void)
int rc;
int orig_error_reporting;
- int (*orig_activate)(TSRMLS_D) = sapi_module.activate;
- int (*orig_deactivate)(TSRMLS_D) = sapi_module.deactivate;
- void (*orig_register_server_variables)(zval *track_vars_array TSRMLS_DC) = sapi_module.register_server_variables;
- int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC) = sapi_module.header_handler;
- int (*orig_send_headers)(sapi_headers_struct *sapi_headers TSRMLS_DC) = sapi_module.send_headers;
- void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC)= sapi_module.send_header;
- char *(*orig_getenv)(char *name, size_t name_len TSRMLS_DC) = sapi_module.getenv;
+ int (*orig_activate)() = sapi_module.activate;
+ int (*orig_deactivate)() = sapi_module.deactivate;
+ void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
+ int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
+ int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
+ void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
+ char *(*orig_getenv)(char *name, size_t name_len) = sapi_module.getenv;
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
void (*orig_flush)(void *server_context) = sapi_module.flush;
uint32_t orig_compiler_options = CG(compiler_options);
@@ -4787,7 +4859,11 @@ ZEND_EXT_API zend_extension zend_extension_entry = {
accel_startup, /* startup */
NULL, /* shutdown */
NULL, /* per-script activation */
+#ifdef HAVE_JIT
+ accel_deactivate, /* per-script deactivation */
+#else
NULL, /* per-script deactivation */
+#endif
NULL, /* message handler */
NULL, /* op_array handler */
NULL, /* extended statement handler */
diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h
index c2f95d7c41..bb884d9cc9 100644
--- a/ext/opcache/ZendAccelerator.h
+++ b/ext/opcache/ZendAccelerator.h
@@ -191,6 +191,12 @@ typedef struct _zend_accel_directives {
#ifdef ZEND_WIN32
char *cache_id;
#endif
+#ifdef HAVE_JIT
+ zend_long jit;
+ zend_long jit_buffer_size;
+ zend_long jit_debug;
+ zend_long jit_bisect_limit;
+#endif
} zend_accel_directives;
typedef struct _zend_accel_globals {
@@ -221,6 +227,9 @@ typedef struct _zend_accel_globals {
void *arena_mem;
zend_persistent_script *current_persistent_script;
zend_bool is_immutable_class;
+#ifdef HAVE_JIT
+ zend_bool jit_enabled;
+#endif
/* cache to save hash lookup on the same INCLUDE opcode */
const zend_op *cache_opline;
zend_persistent_script *cache_persistent_script;
@@ -321,4 +330,19 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type);
zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str);
+/* memory write protection */
+#define SHM_PROTECT() \
+ do { \
+ if (ZCG(accel_directives).protect_memory) { \
+ zend_accel_shared_protect(1); \
+ } \
+ } while (0)
+
+#define SHM_UNPROTECT() \
+ do { \
+ if (ZCG(accel_directives).protect_memory) { \
+ zend_accel_shared_protect(0); \
+ } \
+ } while (0)
+
#endif /* ZEND_ACCELERATOR_H */
diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4
index 6c40cafc1c..5e61575d48 100644
--- a/ext/opcache/config.m4
+++ b/ext/opcache/config.m4
@@ -11,6 +11,13 @@ PHP_ARG_ENABLE([huge-code-pages],
[yes],
[no])
+PHP_ARG_ENABLE([opcache-jit],
+ [whether to enable JIT],
+ [AS_HELP_STRING([--disable-opcache-jit],
+ [Disable JIT])],
+ [yes],
+ [no])
+
if test "$PHP_OPCACHE" != "no"; then
dnl Always build as shared extension
@@ -20,6 +27,67 @@ if test "$PHP_OPCACHE" != "no"; then
AC_DEFINE(HAVE_HUGE_CODE_PAGES, 1, [Define to enable copying PHP CODE pages into HUGE PAGES (experimental)])
fi
+ if test "$PHP_OPCACHE_JIT" = "yes"; then
+ case $host_cpu in
+ x86*)
+ ;;
+ *)
+ AC_MSG_WARN([JIT not supported by host architecture])
+ PHP_OPCACHE_JIT=no
+ ;;
+ esac
+ fi
+
+ if test "$PHP_OPCACHE_JIT" = "yes"; then
+ AC_DEFINE(HAVE_JIT, 1, [Define to enable JIT])
+ ZEND_JIT_SRC="jit/zend_jit.c jit/zend_jit_vm_helpers.c"
+
+ dnl Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *"Mach-O 64-bit"*)
+ DASM_FLAGS="-D X64APPLE=1 -D X64=1"
+ ;;
+ *64-bit*)
+ DASM_FLAGS="-D X64=1"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+
+ if test "$enable_zts" = "yes"; then
+ DASM_FLAGS="$DASM_FLAGS -D ZTS=1"
+ fi
+
+ PHP_SUBST(DASM_FLAGS)
+
+ AC_MSG_CHECKING(for opagent in default path)
+ for i in /usr/local /usr; do
+ if test -r $i/include/opagent.h; then
+ OPAGENT_DIR=$i
+ AC_MSG_RESULT(found in $i)
+ break
+ fi
+ done
+ if test -z "$OPAGENT_DIR"; then
+ AC_MSG_RESULT(not found)
+ else
+ PHP_CHECK_LIBRARY(opagent, op_write_native_code,
+ [
+ AC_DEFINE(HAVE_OPROFILE,1,[ ])
+ PHP_ADD_INCLUDE($OPAGENT_DIR/include)
+ PHP_ADD_LIBRARY_WITH_PATH(opagent, $OPAGENT_DIR/$PHP_LIBDIR/oprofile, OPCACHE_SHARED_LIBADD)
+ PHP_SUBST(OPCACHE_SHARED_LIBADD)
+ ],[
+ AC_MSG_RESULT(not found)
+ ],[
+ -L$OPAGENT_DIR/$PHP_LIBDIR/oprofile
+ ])
+ fi
+
+ fi
+
AC_CHECK_FUNCS([mprotect])
AC_MSG_CHECKING(for sysvipc shared memory support)
@@ -234,8 +302,7 @@ int main() {
shared_alloc_mmap.c \
shared_alloc_posix.c \
Optimizer/zend_optimizer.c \
- Optimizer/pass1_5.c \
- Optimizer/pass2.c \
+ Optimizer/pass1.c \
Optimizer/pass3.c \
Optimizer/optimize_func_calls.c \
Optimizer/block_pass.c \
@@ -254,10 +321,16 @@ int main() {
Optimizer/dce.c \
Optimizer/escape_analysis.c \
Optimizer/compact_vars.c \
- Optimizer/zend_dump.c,
+ Optimizer/zend_dump.c \
+ $ZEND_JIT_SRC,
shared,,-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1,,yes)
PHP_ADD_BUILD_DIR([$ext_builddir/Optimizer], 1)
PHP_ADD_EXTENSION_DEP(opcache, pcre)
+
+ if test "$PHP_OPCACHE_JIT" = "yes"; then
+ PHP_ADD_BUILD_DIR([$ext_builddir/jit], 1)
+ PHP_ADD_MAKEFILE_FRAGMENT($ext_srcdir/jit/Makefile.frag)
+ fi
PHP_SUBST(OPCACHE_SHARED_LIBADD)
fi
diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32
index fba1b1bef1..7c67ccf0f6 100644
--- a/ext/opcache/config.w32
+++ b/ext/opcache/config.w32
@@ -1,9 +1,10 @@
ARG_ENABLE("opcache", "whether to enable Zend OPcache support", "yes");
-/* var PHP_OPCACHE_PGO = false; */
if (PHP_OPCACHE != "no") {
+ ARG_ENABLE("opcache-jit", "whether to enable JIT", "yes");
+
ZEND_EXTENSION('opcache', "\
ZendAccelerator.c \
zend_accelerator_blacklist.c \
@@ -17,9 +18,29 @@ if (PHP_OPCACHE != "no") {
zend_shared_alloc.c \
shared_alloc_win32.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
- ADD_SOURCES(configure_module_dirname + "/Optimizer", "zend_optimizer.c pass1_5.c pass2.c pass3.c optimize_func_calls.c block_pass.c optimize_temp_vars_5.c nop_removal.c compact_literals.c zend_cfg.c zend_dfg.c dfa_pass.c zend_ssa.c zend_inference.c zend_func_info.c zend_call_graph.c sccp.c scdf.c dce.c escape_analysis.c compact_vars.c zend_dump.c", "opcache", "OptimizerObj");
+ if (PHP_OPCACHE_JIT == "yes") {
+ if (CHECK_HEADER_ADD_INCLUDE("dynasm/dasm_x86.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) {
+ var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1";
+ if (PHP_ZTS == "yes") {
+ dasm_flags += " -D ZTS=1";
+ }
+ DEFINE("DASM_FLAGS", dasm_flags);
+
+ AC_DEFINE('HAVE_JIT', 1, 'Define to enable JIT');
+ /* XXX read this dynamically */
+ /*ADD_FLAG("CFLAGS_OPCACHE", "/D DASM_VERSION=10400");*/
+
+ ADD_MAKEFILE_FRAGMENT(configure_module_dirname + "\\jit\\Makefile.frag.w32");
+ ADD_SOURCES(configure_module_dirname + "\\jit", "zend_jit.c zend_jit_vm_helpers.c", "opcache", "opcache_jit");
+ } else {
+ WARNING("JIT not enabled, headers not found");
+ }
+ }
+
+ ADD_SOURCES(configure_module_dirname + "/Optimizer", "zend_optimizer.c pass1.c pass3.c optimize_func_calls.c block_pass.c optimize_temp_vars_5.c nop_removal.c compact_literals.c zend_cfg.c zend_dfg.c dfa_pass.c zend_ssa.c zend_inference.c zend_func_info.c zend_call_graph.c zend_dump.c escape_analysis.c compact_vars.c dce.c sccp.c scdf.c", "opcache", "OptimizerObj");
ADD_FLAG('CFLAGS_OPCACHE', "/I " + configure_module_dirname);
}
+
diff --git a/ext/opcache/jit/Makefile.frag b/ext/opcache/jit/Makefile.frag
new file mode 100644
index 0000000000..02e44c2654
--- /dev/null
+++ b/ext/opcache/jit/Makefile.frag
@@ -0,0 +1,17 @@
+
+$(builddir)/minilua: $(srcdir)/jit/dynasm/minilua.c
+ $(CC) $(srcdir)/jit/dynasm/minilua.c -lm -o $@
+
+$(builddir)/jit/zend_jit_x86.c: $(srcdir)/jit/zend_jit_x86.dasc $(srcdir)/jit/dynasm/*.lua $(builddir)/minilua
+ $(builddir)/minilua $(srcdir)/jit/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ $(srcdir)/jit/zend_jit_x86.dasc
+
+$(builddir)/jit/zend_jit.lo: \
+ $(builddir)/jit/zend_jit_x86.c \
+ $(srcdir)/jit/zend_jit_helpers.c \
+ $(srcdir)/jit/zend_jit_disasm_x86.c \
+ $(srcdir)/jit/zend_jit_gdb.c \
+ $(srcdir)/jit/zend_jit_perf_dump.c \
+ $(srcdir)/jit/zend_jit_oprofile.c \
+ $(srcdir)/jit/zend_jit_vtune.c \
+ $(srcdir)/jit/zend_elf.c
+
diff --git a/ext/opcache/jit/Makefile.frag.w32 b/ext/opcache/jit/Makefile.frag.w32
new file mode 100644
index 0000000000..282f81bb74
--- /dev/null
+++ b/ext/opcache/jit/Makefile.frag.w32
@@ -0,0 +1,16 @@
+$(BUILD_DIR)\\minilua.exe: ext\opcache\jit\dynasm\minilua.c
+ @if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe
+ $(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\dynasm\minilua.c
+
+ext\opcache\jit\zend_jit_x86.c: ext\opcache\jit\zend_jit_x86.dasc $(BUILD_DIR)\\minilua.exe
+ @if exist ext\opcache\jit\zend_jit_x86.c del ext\opcache\jit\zend_jit_x86.c
+ $(BUILD_DIR)\\minilua.exe ext/opcache/jit/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ ext/opcache/jit/zend_jit_x86.dasc
+
+$(BUILD_DIR)\opcache_jit\zend_jit.obj: \
+ ext/opcache/jit/zend_jit_x86.c \
+ ext/opcache/jit/zend_jit_helpers.c \
+ ext/opcache/jit/zend_jit_disasm_x86.c \
+ ext/opcache/jit/zend_jit_gdb.c \
+ ext/opcache/jit/zend_jit_perf_dump.c \
+ ext/opcache/jit/zend_jit_oprofile.c \
+ ext/opcache/jit/zend_jit_vtune.c
diff --git a/ext/opcache/jit/dynasm/dasm_arm.h b/ext/opcache/jit/dynasm/dasm_arm.h
new file mode 100644
index 0000000000..0fa69ac06f
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_arm.h
@@ -0,0 +1,456 @@
+/*
+** DynASM ARM encoding engine.
+** Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH "arm"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC,
+ DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+static int dasm_imm12(unsigned int n)
+{
+ int i;
+ for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30))
+ if (n <= 255) return (int)(n + (i << 8));
+ return -1;
+}
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM:
+ case DASM_IMM16:
+#ifdef DASM_CHECKS
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+ if ((ins & 0x8000))
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ case DASM_IMMV8:
+ CK((n & 3) == 0, RANGE_I);
+ n >>= 2;
+ case DASM_IMML8:
+ case DASM_IMML12:
+ CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) :
+ (((-n)>>((ins>>5)&31)) == 0), RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM12:
+ CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMM12: case DASM_IMM16:
+ case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4;
+ patchrel:
+ if ((ins & 0x800) == 0) {
+ CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL);
+ cp[-1] |= ((n >> 2) & 0x00ffffff);
+ } else if ((ins & 0x1000)) {
+ CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL);
+ goto patchimml8;
+ } else if ((ins & 0x2000) == 0) {
+ CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL);
+ goto patchimml;
+ } else {
+ CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL);
+ n >>= 2;
+ goto patchimml;
+ }
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMM:
+ cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ case DASM_IMM12:
+ cp[-1] |= dasm_imm12((unsigned int)n);
+ break;
+ case DASM_IMM16:
+ cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff);
+ break;
+ case DASM_IMML8: patchimml8:
+ cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) :
+ ((-n & 0x0f) | ((-n & 0xf0) << 4));
+ break;
+ case DASM_IMML12: case DASM_IMMV8: patchimml:
+ cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n);
+ break;
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/ext/opcache/jit/dynasm/dasm_arm.lua b/ext/opcache/jit/dynasm/dasm_arm.lua
new file mode 100644
index 0000000000..e2ed922a3c
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_arm.lua
@@ -0,0 +1,1125 @@
+------------------------------------------------------------------------------
+-- DynASM ARM module.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+ arch = "arm",
+ description = "DynASM ARM module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable, rawget = assert, setmetatable, rawget
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
+local concat, sort, insert = table.concat, table.sort, table.insert
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local ror, tohex = bit.ror, bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n <= 0x000fffff then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ if n <= 0x000fffff then
+ insert(actlist, pos+1, n)
+ n = map_action.ESC * 0x10000
+ end
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+
+-- Ext. register name -> int. name.
+local map_archdef = { sp = "r13", lr = "r14", pc = "r15", }
+
+-- Int. register name -> ext. name.
+local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", }
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ return map_reg_rev[s] or s
+end
+
+local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, }
+
+local map_cond = {
+ eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7,
+ hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14,
+ hs = 2, lo = 3,
+}
+
+------------------------------------------------------------------------------
+
+-- Template strings for ARM instructions.
+local map_op = {
+ -- Basic data processing instructions.
+ and_3 = "e0000000DNPs",
+ eor_3 = "e0200000DNPs",
+ sub_3 = "e0400000DNPs",
+ rsb_3 = "e0600000DNPs",
+ add_3 = "e0800000DNPs",
+ adc_3 = "e0a00000DNPs",
+ sbc_3 = "e0c00000DNPs",
+ rsc_3 = "e0e00000DNPs",
+ tst_2 = "e1100000NP",
+ teq_2 = "e1300000NP",
+ cmp_2 = "e1500000NP",
+ cmn_2 = "e1700000NP",
+ orr_3 = "e1800000DNPs",
+ mov_2 = "e1a00000DPs",
+ bic_3 = "e1c00000DNPs",
+ mvn_2 = "e1e00000DPs",
+
+ and_4 = "e0000000DNMps",
+ eor_4 = "e0200000DNMps",
+ sub_4 = "e0400000DNMps",
+ rsb_4 = "e0600000DNMps",
+ add_4 = "e0800000DNMps",
+ adc_4 = "e0a00000DNMps",
+ sbc_4 = "e0c00000DNMps",
+ rsc_4 = "e0e00000DNMps",
+ tst_3 = "e1100000NMp",
+ teq_3 = "e1300000NMp",
+ cmp_3 = "e1500000NMp",
+ cmn_3 = "e1700000NMp",
+ orr_4 = "e1800000DNMps",
+ mov_3 = "e1a00000DMps",
+ bic_4 = "e1c00000DNMps",
+ mvn_3 = "e1e00000DMps",
+
+ lsl_3 = "e1a00000DMws",
+ lsr_3 = "e1a00020DMws",
+ asr_3 = "e1a00040DMws",
+ ror_3 = "e1a00060DMws",
+ rrx_2 = "e1a00060DMs",
+
+ -- Multiply and multiply-accumulate.
+ mul_3 = "e0000090NMSs",
+ mla_4 = "e0200090NMSDs",
+ umaal_4 = "e0400090DNMSs", -- v6
+ mls_4 = "e0600090DNMSs", -- v6T2
+ umull_4 = "e0800090DNMSs",
+ umlal_4 = "e0a00090DNMSs",
+ smull_4 = "e0c00090DNMSs",
+ smlal_4 = "e0e00090DNMSs",
+
+ -- Halfword multiply and multiply-accumulate.
+ smlabb_4 = "e1000080NMSD", -- v5TE
+ smlatb_4 = "e10000a0NMSD", -- v5TE
+ smlabt_4 = "e10000c0NMSD", -- v5TE
+ smlatt_4 = "e10000e0NMSD", -- v5TE
+ smlawb_4 = "e1200080NMSD", -- v5TE
+ smulwb_3 = "e12000a0NMS", -- v5TE
+ smlawt_4 = "e12000c0NMSD", -- v5TE
+ smulwt_3 = "e12000e0NMS", -- v5TE
+ smlalbb_4 = "e1400080NMSD", -- v5TE
+ smlaltb_4 = "e14000a0NMSD", -- v5TE
+ smlalbt_4 = "e14000c0NMSD", -- v5TE
+ smlaltt_4 = "e14000e0NMSD", -- v5TE
+ smulbb_3 = "e1600080NMS", -- v5TE
+ smultb_3 = "e16000a0NMS", -- v5TE
+ smulbt_3 = "e16000c0NMS", -- v5TE
+ smultt_3 = "e16000e0NMS", -- v5TE
+
+ -- Miscellaneous data processing instructions.
+ clz_2 = "e16f0f10DM", -- v5T
+ rev_2 = "e6bf0f30DM", -- v6
+ rev16_2 = "e6bf0fb0DM", -- v6
+ revsh_2 = "e6ff0fb0DM", -- v6
+ sel_3 = "e6800fb0DNM", -- v6
+ usad8_3 = "e780f010NMS", -- v6
+ usada8_4 = "e7800010NMSD", -- v6
+ rbit_2 = "e6ff0f30DM", -- v6T2
+ movw_2 = "e3000000DW", -- v6T2
+ movt_2 = "e3400000DW", -- v6T2
+ -- Note: the X encodes width-1, not width.
+ sbfx_4 = "e7a00050DMvX", -- v6T2
+ ubfx_4 = "e7e00050DMvX", -- v6T2
+ -- Note: the X encodes the msb field, not the width.
+ bfc_3 = "e7c0001fDvX", -- v6T2
+ bfi_4 = "e7c00010DMvX", -- v6T2
+
+ -- Packing and unpacking instructions.
+ pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6
+ pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6
+ sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6
+ sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6
+ sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6
+ sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6
+ sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6
+ sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6
+ uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6
+ uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6
+ uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6
+ uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6
+ uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6
+ uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6
+
+ -- Saturating instructions.
+ qadd_3 = "e1000050DMN", -- v5TE
+ qsub_3 = "e1200050DMN", -- v5TE
+ qdadd_3 = "e1400050DMN", -- v5TE
+ qdsub_3 = "e1600050DMN", -- v5TE
+ -- Note: the X for ssat* encodes sat_imm-1, not sat_imm.
+ ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6
+ usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6
+ ssat16_3 = "e6a00f30DXM", -- v6
+ usat16_3 = "e6e00f30DXM", -- v6
+
+ -- Parallel addition and subtraction.
+ sadd16_3 = "e6100f10DNM", -- v6
+ sasx_3 = "e6100f30DNM", -- v6
+ ssax_3 = "e6100f50DNM", -- v6
+ ssub16_3 = "e6100f70DNM", -- v6
+ sadd8_3 = "e6100f90DNM", -- v6
+ ssub8_3 = "e6100ff0DNM", -- v6
+ qadd16_3 = "e6200f10DNM", -- v6
+ qasx_3 = "e6200f30DNM", -- v6
+ qsax_3 = "e6200f50DNM", -- v6
+ qsub16_3 = "e6200f70DNM", -- v6
+ qadd8_3 = "e6200f90DNM", -- v6
+ qsub8_3 = "e6200ff0DNM", -- v6
+ shadd16_3 = "e6300f10DNM", -- v6
+ shasx_3 = "e6300f30DNM", -- v6
+ shsax_3 = "e6300f50DNM", -- v6
+ shsub16_3 = "e6300f70DNM", -- v6
+ shadd8_3 = "e6300f90DNM", -- v6
+ shsub8_3 = "e6300ff0DNM", -- v6
+ uadd16_3 = "e6500f10DNM", -- v6
+ uasx_3 = "e6500f30DNM", -- v6
+ usax_3 = "e6500f50DNM", -- v6
+ usub16_3 = "e6500f70DNM", -- v6
+ uadd8_3 = "e6500f90DNM", -- v6
+ usub8_3 = "e6500ff0DNM", -- v6
+ uqadd16_3 = "e6600f10DNM", -- v6
+ uqasx_3 = "e6600f30DNM", -- v6
+ uqsax_3 = "e6600f50DNM", -- v6
+ uqsub16_3 = "e6600f70DNM", -- v6
+ uqadd8_3 = "e6600f90DNM", -- v6
+ uqsub8_3 = "e6600ff0DNM", -- v6
+ uhadd16_3 = "e6700f10DNM", -- v6
+ uhasx_3 = "e6700f30DNM", -- v6
+ uhsax_3 = "e6700f50DNM", -- v6
+ uhsub16_3 = "e6700f70DNM", -- v6
+ uhadd8_3 = "e6700f90DNM", -- v6
+ uhsub8_3 = "e6700ff0DNM", -- v6
+
+ -- Load/store instructions.
+ str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL",
+ strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL",
+ ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL",
+ ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL",
+ strh_2 = "e00000b0DL", strh_3 = "e00000b0DL",
+ ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL",
+ ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE
+ ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL",
+ strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE
+ ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL",
+
+ ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR",
+ ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR",
+ ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR",
+ ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR",
+ stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR",
+ stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR",
+ stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR",
+ stmib_2 = "e9800000oR", stmed_2 = "e9800000oR",
+ pop_1 = "e8bd0000R", push_1 = "e92d0000R",
+
+ -- Branch instructions.
+ b_1 = "ea000000B",
+ bl_1 = "eb000000B",
+ blx_1 = "e12fff30C",
+ bx_1 = "e12fff10M",
+
+ -- Miscellaneous instructions.
+ nop_0 = "e1a00000",
+ mrs_1 = "e10f0000D",
+ bkpt_1 = "e1200070K", -- v5T
+ svc_1 = "ef000000T", swi_1 = "ef000000T",
+ ud_0 = "e7f001f0",
+
+ -- VFP instructions.
+ ["vadd.f32_3"] = "ee300a00dnm",
+ ["vadd.f64_3"] = "ee300b00Gdnm",
+ ["vsub.f32_3"] = "ee300a40dnm",
+ ["vsub.f64_3"] = "ee300b40Gdnm",
+ ["vmul.f32_3"] = "ee200a00dnm",
+ ["vmul.f64_3"] = "ee200b00Gdnm",
+ ["vnmul.f32_3"] = "ee200a40dnm",
+ ["vnmul.f64_3"] = "ee200b40Gdnm",
+ ["vmla.f32_3"] = "ee000a00dnm",
+ ["vmla.f64_3"] = "ee000b00Gdnm",
+ ["vmls.f32_3"] = "ee000a40dnm",
+ ["vmls.f64_3"] = "ee000b40Gdnm",
+ ["vnmla.f32_3"] = "ee100a40dnm",
+ ["vnmla.f64_3"] = "ee100b40Gdnm",
+ ["vnmls.f32_3"] = "ee100a00dnm",
+ ["vnmls.f64_3"] = "ee100b00Gdnm",
+ ["vdiv.f32_3"] = "ee800a00dnm",
+ ["vdiv.f64_3"] = "ee800b00Gdnm",
+
+ ["vabs.f32_2"] = "eeb00ac0dm",
+ ["vabs.f64_2"] = "eeb00bc0Gdm",
+ ["vneg.f32_2"] = "eeb10a40dm",
+ ["vneg.f64_2"] = "eeb10b40Gdm",
+ ["vsqrt.f32_2"] = "eeb10ac0dm",
+ ["vsqrt.f64_2"] = "eeb10bc0Gdm",
+ ["vcmp.f32_2"] = "eeb40a40dm",
+ ["vcmp.f64_2"] = "eeb40b40Gdm",
+ ["vcmpe.f32_2"] = "eeb40ac0dm",
+ ["vcmpe.f64_2"] = "eeb40bc0Gdm",
+ ["vcmpz.f32_1"] = "eeb50a40d",
+ ["vcmpz.f64_1"] = "eeb50b40Gd",
+ ["vcmpze.f32_1"] = "eeb50ac0d",
+ ["vcmpze.f64_1"] = "eeb50bc0Gd",
+
+ vldr_2 = "ed100a00dl|ed100b00Gdl",
+ vstr_2 = "ed000a00dl|ed000b00Gdl",
+ vldm_2 = "ec900a00or",
+ vldmia_2 = "ec900a00or",
+ vldmdb_2 = "ed100a00or",
+ vpop_1 = "ecbd0a00r",
+ vstm_2 = "ec800a00or",
+ vstmia_2 = "ec800a00or",
+ vstmdb_2 = "ed000a00or",
+ vpush_1 = "ed2d0a00r",
+
+ ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only
+ ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only
+ vmov_2 = "ee100a10Dn|ee000a10nD",
+ vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN",
+
+ vmrs_0 = "eef1fa10",
+ vmrs_1 = "eef10a10D",
+ vmsr_1 = "eee10a10D",
+
+ ["vcvt.s32.f32_2"] = "eebd0ac0dm",
+ ["vcvt.s32.f64_2"] = "eebd0bc0dGm",
+ ["vcvt.u32.f32_2"] = "eebc0ac0dm",
+ ["vcvt.u32.f64_2"] = "eebc0bc0dGm",
+ ["vcvtr.s32.f32_2"] = "eebd0a40dm",
+ ["vcvtr.s32.f64_2"] = "eebd0b40dGm",
+ ["vcvtr.u32.f32_2"] = "eebc0a40dm",
+ ["vcvtr.u32.f64_2"] = "eebc0b40dGm",
+ ["vcvt.f32.s32_2"] = "eeb80ac0dm",
+ ["vcvt.f64.s32_2"] = "eeb80bc0GdFm",
+ ["vcvt.f32.u32_2"] = "eeb80a40dm",
+ ["vcvt.f64.u32_2"] = "eeb80b40GdFm",
+ ["vcvt.f32.f64_2"] = "eeb70bc0dGm",
+ ["vcvt.f64.f32_2"] = "eeb70ac0GdFm",
+
+ -- VFPv4 only:
+ ["vfma.f32_3"] = "eea00a00dnm",
+ ["vfma.f64_3"] = "eea00b00Gdnm",
+ ["vfms.f32_3"] = "eea00a40dnm",
+ ["vfms.f64_3"] = "eea00b40Gdnm",
+ ["vfnma.f32_3"] = "ee900a40dnm",
+ ["vfnma.f64_3"] = "ee900b40Gdnm",
+ ["vfnms.f32_3"] = "ee900a00dnm",
+ ["vfnms.f64_3"] = "ee900b00Gdnm",
+
+ -- NYI: Advanced SIMD instructions.
+
+ -- NYI: I have no need for these instructions right now:
+ -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh
+ -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe
+ -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb
+ -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2
+}
+
+-- Add mnemonics for "s" variants.
+do
+ local t = {}
+ for k,v in pairs(map_op) do
+ if sub(v, -1) == "s" then
+ local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2)
+ t[sub(k, 1, -3).."s"..sub(k, -2)] = v2
+ end
+ end
+ for k,v in pairs(t) do
+ map_op[k] = v
+ end
+end
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+ local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local r = match(expr, "^r(1?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 15 then return r, tp end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_gpr_pm(expr)
+ local pm, expr2 = match(expr, "^([+-]?)(.*)$")
+ return parse_gpr(expr2), (pm == "-")
+end
+
+local function parse_vr(expr, tp)
+ local t, r = match(expr, "^([sd])([0-9]+)$")
+ if t == tp then
+ r = tonumber(r)
+ if r <= 31 then
+ if t == "s" then return shr(r, 1), band(r, 1) end
+ return band(r, 15), shr(r, 4)
+ end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_reglist(reglist)
+ reglist = match(reglist, "^{%s*([^}]*)}$")
+ if not reglist then werror("register list expected") end
+ local rr = 0
+ for p in gmatch(reglist..",", "%s*([^,]*),") do
+ local rbit = shl(1, parse_gpr(gsub(p, "%s+$", "")))
+ if band(rr, rbit) ~= 0 then
+ werror("duplicate register `"..p.."'")
+ end
+ rr = rr + rbit
+ end
+ return rr
+end
+
+local function parse_vrlist(reglist)
+ local ta, ra, tb, rb = match(reglist,
+ "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$")
+ ra, rb = tonumber(ra), tonumber(rb)
+ if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then
+ local nr = rb+1 - ra
+ if ta == "s" then
+ return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr
+ else
+ return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100
+ end
+ end
+ werror("register list expected")
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = tonumber(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+ return 0
+ end
+end
+
+local function parse_imm12(imm)
+ local n = tonumber(imm)
+ if n then
+ local m = band(n)
+ for i=0,-15,-1 do
+ if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end
+ m = ror(m, 2)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM12", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm16(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = tonumber(imm)
+ if n then
+ if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM16", 32*16, imm)
+ return 0
+ end
+end
+
+local function parse_imm_load(imm, ext)
+ local n = tonumber(imm)
+ if n then
+ if ext then
+ if n >= -255 and n <= 255 then
+ local up = 0x00800000
+ if n < 0 then n = -n; up = 0 end
+ return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up
+ end
+ else
+ if n >= -4095 and n <= 4095 then
+ if n >= 0 then return n+0x00800000 end
+ return -n
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm)
+ return 0
+ end
+end
+
+local function parse_shift(shift, gprok)
+ if shift == "rrx" then
+ return 3 * 32
+ else
+ local s, s2 = match(shift, "^(%S+)%s*(.*)$")
+ s = map_shift[s]
+ if not s then werror("expected shift operand") end
+ if sub(s2, 1, 1) == "#" then
+ return parse_imm(s2, 5, 7, 0, false) + shl(s, 5)
+ else
+ if not gprok then werror("expected immediate shift operand") end
+ return shl(parse_gpr(s2), 8) + shl(s, 5) + 16
+ end
+ end
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+local function parse_load(params, nparams, n, op)
+ local oplo = band(op, 255)
+ local ext, ldrd = (oplo ~= 0), (oplo == 208)
+ local d
+ if (ldrd or oplo == 240) then
+ d = band(shr(op, 12), 15)
+ if band(d, 1) ~= 0 then werror("odd destination register") end
+ end
+ local pn = params[n]
+ local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
+ local p2 = params[n+1]
+ if not p1 then
+ if not p2 then
+ if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then
+ local mode, n, s = parse_label(pn, false)
+ waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1)
+ return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0)
+ end
+ local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local d, tp = parse_gpr(reg)
+ if tp then
+ waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12),
+ format(tp.ctypefmt, tailr))
+ return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0)
+ end
+ end
+ end
+ werror("expected address operand")
+ end
+ if wb == "!" then op = op + 0x00200000 end
+ if p2 then
+ if wb == "!" then werror("bad use of '!'") end
+ local p3 = params[n+2]
+ op = op + shl(parse_gpr(p1), 16)
+ local imm = match(p2, "^#(.*)$")
+ if imm then
+ local m = parse_imm_load(imm, ext)
+ if p3 then werror("too many parameters") end
+ op = op + m + (ext and 0x00400000 or 0)
+ else
+ local m, neg = parse_gpr_pm(p2)
+ if ldrd and (m == d or m-1 == d) then werror("register conflict") end
+ op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
+ if p3 then op = op + parse_shift(p3) end
+ end
+ else
+ local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$")
+ op = op + shl(parse_gpr(p1a), 16) + 0x01000000
+ if p2 ~= "" then
+ local imm = match(p2, "^,%s*#(.*)$")
+ if imm then
+ local m = parse_imm_load(imm, ext)
+ op = op + m + (ext and 0x00400000 or 0)
+ else
+ local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$")
+ local m, neg = parse_gpr_pm(p2a)
+ if ldrd and (m == d or m-1 == d) then werror("register conflict") end
+ op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000)
+ if p3 ~= "" then
+ if ext then werror("too many parameters") end
+ op = op + parse_shift(p3)
+ end
+ end
+ else
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + (ext and 0x00c00000 or 0x00800000)
+ end
+ end
+ return op
+end
+
+local function parse_vload(q)
+ local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$")
+ if reg then
+ local d = shl(parse_gpr(reg), 16)
+ if imm == "" then return d end
+ imm = match(imm, "^,%s*#(.*)$")
+ if imm then
+ local n = tonumber(imm)
+ if n then
+ if n >= -1020 and n <= 1020 and n%4 == 0 then
+ return d + (n >= 0 and n/4+0x00800000 or -n/4)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMMV8", 32768 + 32*8, imm)
+ return d
+ end
+ end
+ else
+ if match(q, "^[<>=%-]") or match(q, "^extern%s+") then
+ local mode, n, s = parse_label(q, false)
+ waction("REL_"..mode, n + 0x2800, s, 1)
+ return 15 * 65536
+ end
+ local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local d, tp = parse_gpr(reg)
+ if tp then
+ waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr))
+ return shl(d, 16)
+ end
+ end
+ end
+ werror("expected address operand")
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+local function parse_template(params, template, nparams, pos)
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n = 1
+ local vr = "s"
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ local q = params[n]
+ if p == "D" then
+ op = op + shl(parse_gpr(q), 12); n = n + 1
+ elseif p == "N" then
+ op = op + shl(parse_gpr(q), 16); n = n + 1
+ elseif p == "S" then
+ op = op + shl(parse_gpr(q), 8); n = n + 1
+ elseif p == "M" then
+ op = op + parse_gpr(q); n = n + 1
+ elseif p == "d" then
+ local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1
+ elseif p == "n" then
+ local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1
+ elseif p == "m" then
+ local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1
+ elseif p == "P" then
+ local imm = match(q, "^#(.*)$")
+ if imm then
+ op = op + parse_imm12(imm) + 0x02000000
+ else
+ op = op + parse_gpr(q)
+ end
+ n = n + 1
+ elseif p == "p" then
+ op = op + parse_shift(q, true); n = n + 1
+ elseif p == "L" then
+ op = parse_load(params, nparams, n, op)
+ elseif p == "l" then
+ op = op + parse_vload(q)
+ elseif p == "B" then
+ local mode, n, s = parse_label(q, false)
+ waction("REL_"..mode, n, s, 1)
+ elseif p == "C" then -- blx gpr vs. blx label.
+ if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then
+ op = op + parse_gpr(q)
+ else
+ if op < 0xe0000000 then werror("unconditional instruction") end
+ local mode, n, s = parse_label(q, false)
+ waction("REL_"..mode, n, s, 1)
+ op = 0xfa000000
+ end
+ elseif p == "F" then
+ vr = "s"
+ elseif p == "G" then
+ vr = "d"
+ elseif p == "o" then
+ local r, wb = match(q, "^([^!]*)(!?)$")
+ op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0)
+ n = n + 1
+ elseif p == "R" then
+ op = op + parse_reglist(q); n = n + 1
+ elseif p == "r" then
+ op = op + parse_vrlist(q); n = n + 1
+ elseif p == "W" then
+ op = op + parse_imm16(q); n = n + 1
+ elseif p == "v" then
+ op = op + parse_imm(q, 5, 7, 0, false); n = n + 1
+ elseif p == "w" then
+ local imm = match(q, "^#(.*)$")
+ if imm then
+ op = op + parse_imm(q, 5, 7, 0, false); n = n + 1
+ else
+ op = op + shl(parse_gpr(q), 8) + 16
+ end
+ elseif p == "X" then
+ op = op + parse_imm(q, 5, 16, 0, false); n = n + 1
+ elseif p == "Y" then
+ local imm = tonumber(match(q, "^#(.*)$")); n = n + 1
+ if not imm or shr(imm, 8) ~= 0 then
+ werror("bad immediate operand")
+ end
+ op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f)
+ elseif p == "K" then
+ local imm = tonumber(match(q, "^#(.*)$")); n = n + 1
+ if not imm or shr(imm, 16) ~= 0 then
+ werror("bad immediate operand")
+ end
+ op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f)
+ elseif p == "T" then
+ op = op + parse_imm(q, 24, 0, 0, false); n = n + 1
+ elseif p == "s" then
+ -- Ignored.
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+map_op[".template__"] = function(params, template, nparams)
+ if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 3 positions.
+ if secpos+3 > maxsecpos then wflush() end
+ local pos = wpos()
+ local lpos, apos, spos = #actlist, #actargs, secpos
+
+ local ok, err
+ for t in gmatch(template, "[^|]+") do
+ ok, err = pcall(parse_template, params, t, nparams, pos)
+ if ok then return end
+ secpos = spos
+ actlist[lpos+1] = nil
+ actlist[lpos+2] = nil
+ actlist[lpos+3] = nil
+ actargs[apos+1] = nil
+ actargs[apos+2] = nil
+ actargs[apos+3] = nil
+ end
+ error(err, 0)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = function(t, k)
+ local v = map_coreop[k]
+ if v then return v end
+ local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$")
+ local cv = map_cond[cc]
+ if cv then
+ local v = rawget(t, k1..k2)
+ if type(v) == "string" then
+ local scv = format("%x", cv)
+ return gsub(scv..sub(v, 2), "|e", "|"..scv)
+ end
+ end
+ end })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/ext/opcache/jit/dynasm/dasm_arm64.h b/ext/opcache/jit/dynasm/dasm_arm64.h
new file mode 100644
index 0000000000..d64e60a3e6
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_arm64.h
@@ -0,0 +1,518 @@
+/*
+** DynASM ARM64 encoding engine.
+** Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH "arm64"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC,
+ DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+static int dasm_imm12(unsigned int n)
+{
+ if ((n >> 12) == 0)
+ return n;
+ else if ((n & 0xff000fff) == 0)
+ return (n >> 12) | 0x1000;
+ else
+ return -1;
+}
+
+static int dasm_ffs(unsigned long long x)
+{
+ int n = -1;
+ while (x) { x >>= 1; n++; }
+ return n;
+}
+
+static int dasm_imm13(int lo, int hi)
+{
+ int inv = 0, w = 64, s = 0xfff, xa, xb;
+ unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo;
+ unsigned long long m = 1ULL, a, b, c;
+ if (n & 1) { n = ~n; inv = 1; }
+ a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b);
+ xa = dasm_ffs(a); xb = dasm_ffs(b);
+ if (c) {
+ w = dasm_ffs(c) - xa;
+ if (w == 32) m = 0x0000000100000001UL;
+ else if (w == 16) m = 0x0001000100010001UL;
+ else if (w == 8) m = 0x0101010101010101UL;
+ else if (w == 4) m = 0x1111111111111111UL;
+ else if (w == 2) m = 0x5555555555555555UL;
+ else return -1;
+ s = (-2*w & 0x3f) - 1;
+ } else if (!a) {
+ return -1;
+ } else if (xb == -1) {
+ xb = 64;
+ }
+ if ((b-a) * m != n) return -1;
+ if (inv) {
+ return ((w - xb) << 6) | (s+w+xa-xb);
+ } else {
+ return ((w - xa) << 6) | (s+xb-xa);
+ }
+ return -1;
+}
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM:
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+ n >>= ((ins>>10)&31);
+#ifdef DASM_CHECKS
+ if ((ins & 0x8000))
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ case DASM_IMM6:
+ CK((n >> 6) == 0, RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM12:
+ CK(dasm_imm12((unsigned int)n) != -1, RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM13W:
+ CK(dasm_imm13(n, n) != -1, RANGE_I);
+ b[pos++] = n;
+ break;
+ case DASM_IMM13X: {
+ int m = va_arg(ap, int);
+ CK(dasm_imm13(n, m) != -1, RANGE_I);
+ b[pos++] = n;
+ b[pos++] = m;
+ break;
+ }
+ case DASM_IMML: {
+#ifdef DASM_CHECKS
+ int scale = (p[-2] >> 30);
+ CK((!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ||
+ (unsigned int)(n+256) < 512, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W:
+ case DASM_IMML: pos++; break;
+ case DASM_IMM13X: pos += 2; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048));
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4;
+ patchrel:
+ if (!(ins & 0xf800)) { /* B, BL */
+ CK((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, RANGE_REL);
+ cp[-1] |= ((n >> 2) & 0x03ffffff);
+ } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
+ CK((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, RANGE_REL);
+ cp[-1] |= ((n << 3) & 0x00ffffe0);
+ } else if ((ins & 0x3000) == 0x2000) { /* ADR */
+ CK(((n+0x00100000) >> 21) == 0, RANGE_REL);
+ cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29);
+ } else if ((ins & 0x3000) == 0x3000) { /* ADRP */
+ cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29);
+ } else if ((ins & 0x1000)) { /* TBZ, TBNZ */
+ CK((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, RANGE_REL);
+ cp[-1] |= ((n << 3) & 0x0007ffe0);
+ }
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMM:
+ cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ case DASM_IMM6:
+ cp[-1] |= ((n&31) << 19) | ((n&32) << 26);
+ break;
+ case DASM_IMM12:
+ cp[-1] |= (dasm_imm12((unsigned int)n) << 10);
+ break;
+ case DASM_IMM13W:
+ cp[-1] |= (dasm_imm13(n, n) << 10);
+ break;
+ case DASM_IMM13X:
+ cp[-1] |= (dasm_imm13(n, *b++) << 10);
+ break;
+ case DASM_IMML: {
+ int scale = (p[-2] >> 30);
+ cp[-1] |= (!(n & ((1<<scale)-1)) && (unsigned int)(n>>scale) < 4096) ?
+ ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12);
+ break;
+ }
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/ext/opcache/jit/dynasm/dasm_arm64.lua b/ext/opcache/jit/dynasm/dasm_arm64.lua
new file mode 100644
index 0000000000..4a7d8dfeeb
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_arm64.lua
@@ -0,0 +1,1166 @@
+------------------------------------------------------------------------------
+-- DynASM ARM64 module.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+ arch = "arm",
+ description = "DynASM ARM64 module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable, rawget = assert, setmetatable, rawget
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub
+local concat, sort, insert = table.concat, table.sort, table.insert
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local ror, tohex = bit.ror, bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n <= 0x000fffff then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ if n <= 0x000fffff then
+ insert(actlist, pos+1, n)
+ n = map_action.ESC * 0x10000
+ end
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+
+-- Ext. register name -> int. name.
+local map_archdef = { xzr = "@x31", wzr = "@w31", lr = "x30", }
+
+-- Int. register name -> ext. name.
+local map_reg_rev = { ["@x31"] = "xzr", ["@w31"] = "wzr", x30 = "lr", }
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ return map_reg_rev[s] or s
+end
+
+local map_shift = { lsl = 0, lsr = 1, asr = 2, }
+
+local map_extend = {
+ uxtb = 0, uxth = 1, uxtw = 2, uxtx = 3,
+ sxtb = 4, sxth = 5, sxtw = 6, sxtx = 7,
+}
+
+local map_cond = {
+ eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7,
+ hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14,
+ hs = 2, lo = 3,
+}
+
+------------------------------------------------------------------------------
+
+local parse_reg_type
+
+local function parse_reg(expr)
+ if not expr then werror("expected register name") end
+ local tname, ovreg = match(expr, "^([%w_]+):(@?%l%d+)$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local ok31, rt, r = match(expr, "^(@?)([xwqdshb])([123]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 30 or (r == 31 and ok31 ~= "" or (rt ~= "w" and rt ~= "x")) then
+ if not parse_reg_type then
+ parse_reg_type = rt
+ elseif parse_reg_type ~= rt then
+ werror("register size mismatch")
+ end
+ return r, tp
+ end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_reg_base(expr)
+ if expr == "sp" then return 0x3e0 end
+ local base, tp = parse_reg(expr)
+ if parse_reg_type ~= "x" then werror("bad register type") end
+ parse_reg_type = false
+ return shl(base, 5), tp
+end
+
+local parse_ctx = {}
+
+local loadenv = setfenv and function(s)
+ local code = loadstring(s, "")
+ if code then setfenv(code, parse_ctx) end
+ return code
+end or function(s)
+ return load(s, "", nil, parse_ctx)
+end
+
+-- Try to parse simple arithmetic, too, since some basic ops are aliases.
+local function parse_number(n)
+ local x = tonumber(n)
+ if x then return x end
+ local code = loadenv("return "..n)
+ if code then
+ local ok, y = pcall(code)
+ if ok then return y end
+ end
+ return nil
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+ return 0
+ end
+end
+
+local function parse_imm12(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ if shr(n, 12) == 0 then
+ return shl(n, 10)
+ elseif band(n, 0xff000fff) == 0 then
+ return shr(n, 2) + 0x00400000
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM12", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm13(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ local r64 = parse_reg_type == "x"
+ if n and n % 1 == 0 and n >= 0 and n <= 0xffffffff then
+ local inv = false
+ if band(n, 1) == 1 then n = bit.bnot(n); inv = true end
+ local t = {}
+ for i=1,32 do t[i] = band(n, 1); n = shr(n, 1) end
+ local b = table.concat(t)
+ b = b..(r64 and (inv and "1" or "0"):rep(32) or b)
+ local p0, p1, p0a, p1a = b:match("^(0+)(1+)(0*)(1*)")
+ if p0 then
+ local w = p1a == "" and (r64 and 64 or 32) or #p1+#p0a
+ if band(w, w-1) == 0 and b == b:sub(1, w):rep(64/w) then
+ local s = band(-2*w, 0x3f) - 1
+ if w == 64 then s = s + 0x1000 end
+ if inv then
+ return shl(w-#p1-#p0, 16) + shl(s+w-#p1, 10)
+ else
+ return shl(w-#p0, 16) + shl(s+#p1, 10)
+ end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif r64 then
+ waction("IMM13X", 0, format("(unsigned int)(%s)", imm))
+ actargs[#actargs+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm)
+ return 0
+ else
+ waction("IMM13W", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm6(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ if n >= 0 and n <= 63 then
+ return shl(band(n, 0x1f), 19) + (n >= 32 and 0x80000000 or 0)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMM6", 0, imm)
+ return 0
+ end
+end
+
+local function parse_imm_load(imm, scale)
+ local n = parse_number(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n and m >= 0 and m < 0x1000 then
+ return shl(m, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset.
+ elseif n >= -256 and n < 256 then
+ return shl(band(n, 511), 12) -- Unscaled, signed 9 bit offset.
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ waction("IMML", 0, imm)
+ return 0
+ end
+end
+
+local function parse_fpimm(imm)
+ imm = match(imm, "^#(.*)$")
+ if not imm then werror("expected immediate operand") end
+ local n = parse_number(imm)
+ if n then
+ local m, e = math.frexp(n)
+ local s, e2 = 0, band(e-2, 7)
+ if m < 0 then m = -m; s = 0x00100000 end
+ m = m*32-16
+ if m % 1 == 0 and m >= 0 and m <= 15 and sar(shl(e2, 29), 29)+2 == e then
+ return s + shl(e2, 17) + shl(m, 13)
+ end
+ werror("out of range immediate `"..imm.."'")
+ else
+ werror("NYI fpimm action")
+ end
+end
+
+local function parse_shift(expr)
+ local s, s2 = match(expr, "^(%S+)%s*(.*)$")
+ s = map_shift[s]
+ if not s then werror("expected shift operand") end
+ return parse_imm(s2, 6, 10, 0, false) + shl(s, 22)
+end
+
+local function parse_lslx16(expr)
+ local n = match(expr, "^lsl%s*#(%d+)$")
+ n = tonumber(n)
+ if not n then werror("expected shift operand") end
+ if band(n, parse_reg_type == "x" and 0xffffffcf or 0xffffffef) ~= 0 then
+ werror("bad shift amount")
+ end
+ return shl(n, 17)
+end
+
+local function parse_extend(expr)
+ local s, s2 = match(expr, "^(%S+)%s*(.*)$")
+ if s == "lsl" then
+ s = parse_reg_type == "x" and 3 or 2
+ else
+ s = map_extend[s]
+ end
+ if not s then werror("expected extend operand") end
+ return (s2 == "" and 0 or parse_imm(s2, 3, 10, 0, false)) + shl(s, 13)
+end
+
+local function parse_cond(expr, inv)
+ local c = map_cond[expr]
+ if not c then werror("expected condition operand") end
+ return shl(bit.bxor(c, inv), 12)
+end
+
+local function parse_load(params, nparams, n, op)
+ if params[n+2] then werror("too many operands") end
+ local pn, p2 = params[n], params[n+1]
+ local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
+ if not p1 then
+ if not p2 then
+ local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local base, tp = parse_reg_base(reg)
+ if tp then
+ waction("IMML", 0, format(tp.ctypefmt, tailr))
+ return op + base
+ end
+ end
+ end
+ werror("expected address operand")
+ end
+ local scale = shr(op, 30)
+ if p2 then
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + parse_reg_base(p1) + parse_imm(p2, 9, 12, 0, true) + 0x400
+ elseif wb == "!" then
+ local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$")
+ if not p1a then werror("bad use of '!'") end
+ op = op + parse_reg_base(p1a) + parse_imm(p2a, 9, 12, 0, true) + 0xc00
+ else
+ local p1a, p2a = match(p1, "^([^,%s]*)%s*(.*)$")
+ op = op + parse_reg_base(p1a)
+ if p2a ~= "" then
+ local imm = match(p2a, "^,%s*#(.*)$")
+ if imm then
+ op = op + parse_imm_load(imm, scale)
+ else
+ local p2b, p3b, p3s = match(p2a, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$")
+ op = op + shl(parse_reg(p2b), 16) + 0x00200800
+ if parse_reg_type ~= "x" and parse_reg_type ~= "w" then
+ werror("bad index register type")
+ end
+ if p3b == "" then
+ if parse_reg_type ~= "x" then werror("bad index register type") end
+ op = op + 0x6000
+ else
+ if p3s == "" or p3s == "#0" then
+ elseif p3s == "#"..scale then
+ op = op + 0x1000
+ else
+ werror("bad scale")
+ end
+ if parse_reg_type == "x" then
+ if p3b == "lsl" and p3s ~= "" then op = op + 0x6000
+ elseif p3b == "sxtx" then op = op + 0xe000
+ else
+ werror("bad extend/shift specifier")
+ end
+ else
+ if p3b == "uxtw" then op = op + 0x4000
+ elseif p3b == "sxtw" then op = op + 0xc000
+ else
+ werror("bad extend/shift specifier")
+ end
+ end
+ end
+ end
+ else
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + 0x01000000
+ end
+ end
+ return op
+end
+
+local function parse_load_pair(params, nparams, n, op)
+ if params[n+2] then werror("too many operands") end
+ local pn, p2 = params[n], params[n+1]
+ local scale = shr(op, 30) == 0 and 2 or 3
+ local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$")
+ if not p1 then
+ if not p2 then
+ local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local base, tp = parse_reg_base(reg)
+ if tp then
+ waction("IMM", 32768+7*32+15+scale*1024, format(tp.ctypefmt, tailr))
+ return op + base + 0x01000000
+ end
+ end
+ end
+ werror("expected address operand")
+ end
+ if p2 then
+ if wb == "!" then werror("bad use of '!'") end
+ op = op + 0x00800000
+ else
+ local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$")
+ if p1a then p1, p2 = p1a, p2a else p2 = "#0" end
+ op = op + (wb == "!" and 0x01800000 or 0x01000000)
+ end
+ return op + parse_reg_base(p1) + parse_imm(p2, 7, 15, scale, true)
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+local function branch_type(op)
+ if band(op, 0x7c000000) == 0x14000000 then return 0 -- B, BL
+ elseif shr(op, 24) == 0x54 or band(op, 0x7e000000) == 0x34000000 or
+ band(op, 0x3b000000) == 0x18000000 then
+ return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal
+ elseif band(op, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ
+ elseif band(op, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR
+ elseif band(op, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP
+ else
+ assert(false, "unknown branch type")
+ end
+end
+
+------------------------------------------------------------------------------
+
+local map_op, op_template
+
+local function op_alias(opname, f)
+ return function(params, nparams)
+ if not params then return "-> "..opname:sub(1, -3) end
+ f(params, nparams)
+ op_template(params, map_op[opname], nparams)
+ end
+end
+
+local function alias_bfx(p)
+ p[4] = "#("..p[3]:sub(2)..")+("..p[4]:sub(2)..")-1"
+end
+
+local function alias_bfiz(p)
+ parse_reg(p[1])
+ if parse_reg_type == "w" then
+ p[3] = "#-("..p[3]:sub(2)..")%32"
+ p[4] = "#("..p[4]:sub(2)..")-1"
+ else
+ p[3] = "#-("..p[3]:sub(2)..")%64"
+ p[4] = "#("..p[4]:sub(2)..")-1"
+ end
+end
+
+local alias_lslimm = op_alias("ubfm_4", function(p)
+ parse_reg(p[1])
+ local sh = p[3]:sub(2)
+ if parse_reg_type == "w" then
+ p[3] = "#-("..sh..")%32"
+ p[4] = "#31-("..sh..")"
+ else
+ p[3] = "#-("..sh..")%64"
+ p[4] = "#63-("..sh..")"
+ end
+end)
+
+-- Template strings for ARM instructions.
+map_op = {
+ -- Basic data processing instructions.
+ add_3 = "0b000000DNMg|11000000pDpNIg|8b206000pDpNMx",
+ add_4 = "0b000000DNMSg|0b200000DNMXg|8b200000pDpNMXx|8b200000pDpNxMwX",
+ adds_3 = "2b000000DNMg|31000000DpNIg|ab206000DpNMx",
+ adds_4 = "2b000000DNMSg|2b200000DNMXg|ab200000DpNMXx|ab200000DpNxMwX",
+ cmn_2 = "2b00001fNMg|3100001fpNIg|ab20601fpNMx",
+ cmn_3 = "2b00001fNMSg|2b20001fNMXg|ab20001fpNMXx|ab20001fpNxMwX",
+
+ sub_3 = "4b000000DNMg|51000000pDpNIg|cb206000pDpNMx",
+ sub_4 = "4b000000DNMSg|4b200000DNMXg|cb200000pDpNMXx|cb200000pDpNxMwX",
+ subs_3 = "6b000000DNMg|71000000DpNIg|eb206000DpNMx",
+ subs_4 = "6b000000DNMSg|6b200000DNMXg|eb200000DpNMXx|eb200000DpNxMwX",
+ cmp_2 = "6b00001fNMg|7100001fpNIg|eb20601fpNMx",
+ cmp_3 = "6b00001fNMSg|6b20001fNMXg|eb20001fpNMXx|eb20001fpNxMwX",
+
+ neg_2 = "4b0003e0DMg",
+ neg_3 = "4b0003e0DMSg",
+ negs_2 = "6b0003e0DMg",
+ negs_3 = "6b0003e0DMSg",
+
+ adc_3 = "1a000000DNMg",
+ adcs_3 = "3a000000DNMg",
+ sbc_3 = "5a000000DNMg",
+ sbcs_3 = "7a000000DNMg",
+ ngc_2 = "5a0003e0DMg",
+ ngcs_2 = "7a0003e0DMg",
+
+ and_3 = "0a000000DNMg|12000000pDNig",
+ and_4 = "0a000000DNMSg",
+ orr_3 = "2a000000DNMg|32000000pDNig",
+ orr_4 = "2a000000DNMSg",
+ eor_3 = "4a000000DNMg|52000000pDNig",
+ eor_4 = "4a000000DNMSg",
+ ands_3 = "6a000000DNMg|72000000DNig",
+ ands_4 = "6a000000DNMSg",
+ tst_2 = "6a00001fNMg|7200001fNig",
+ tst_3 = "6a00001fNMSg",
+
+ bic_3 = "0a200000DNMg",
+ bic_4 = "0a200000DNMSg",
+ orn_3 = "2a200000DNMg",
+ orn_4 = "2a200000DNMSg",
+ eon_3 = "4a200000DNMg",
+ eon_4 = "4a200000DNMSg",
+ bics_3 = "6a200000DNMg",
+ bics_4 = "6a200000DNMSg",
+
+ movn_2 = "12800000DWg",
+ movn_3 = "12800000DWRg",
+ movz_2 = "52800000DWg",
+ movz_3 = "52800000DWRg",
+ movk_2 = "72800000DWg",
+ movk_3 = "72800000DWRg",
+
+ -- TODO: this doesn't cover all valid immediates for mov reg, #imm.
+ mov_2 = "2a0003e0DMg|52800000DW|320003e0pDig|11000000pDpNg",
+ mov_3 = "2a0003e0DMSg",
+ mvn_2 = "2a2003e0DMg",
+ mvn_3 = "2a2003e0DMSg",
+
+ adr_2 = "10000000DBx",
+ adrp_2 = "90000000DBx",
+
+ csel_4 = "1a800000DNMCg",
+ csinc_4 = "1a800400DNMCg",
+ csinv_4 = "5a800000DNMCg",
+ csneg_4 = "5a800400DNMCg",
+ cset_2 = "1a9f07e0Dcg",
+ csetm_2 = "5a9f03e0Dcg",
+ cinc_3 = "1a800400DNmcg",
+ cinv_3 = "5a800000DNmcg",
+ cneg_3 = "5a800400DNmcg",
+
+ ccmn_4 = "3a400000NMVCg|3a400800N5VCg",
+ ccmp_4 = "7a400000NMVCg|7a400800N5VCg",
+
+ madd_4 = "1b000000DNMAg",
+ msub_4 = "1b008000DNMAg",
+ mul_3 = "1b007c00DNMg",
+ mneg_3 = "1b00fc00DNMg",
+
+ smaddl_4 = "9b200000DxNMwAx",
+ smsubl_4 = "9b208000DxNMwAx",
+ smull_3 = "9b207c00DxNMw",
+ smnegl_3 = "9b20fc00DxNMw",
+ smulh_3 = "9b407c00DNMx",
+ umaddl_4 = "9ba00000DxNMwAx",
+ umsubl_4 = "9ba08000DxNMwAx",
+ umull_3 = "9ba07c00DxNMw",
+ umnegl_3 = "9ba0fc00DxNMw",
+ umulh_3 = "9bc07c00DNMx",
+
+ udiv_3 = "1ac00800DNMg",
+ sdiv_3 = "1ac00c00DNMg",
+
+ -- Bit operations.
+ sbfm_4 = "13000000DN12w|93400000DN12x",
+ bfm_4 = "33000000DN12w|b3400000DN12x",
+ ubfm_4 = "53000000DN12w|d3400000DN12x",
+ extr_4 = "13800000DNM2w|93c00000DNM2x",
+
+ sxtb_2 = "13001c00DNw|93401c00DNx",
+ sxth_2 = "13003c00DNw|93403c00DNx",
+ sxtw_2 = "93407c00DxNw",
+ uxtb_2 = "53001c00DNw",
+ uxth_2 = "53003c00DNw",
+
+ sbfx_4 = op_alias("sbfm_4", alias_bfx),
+ bfxil_4 = op_alias("bfm_4", alias_bfx),
+ ubfx_4 = op_alias("ubfm_4", alias_bfx),
+ sbfiz_4 = op_alias("sbfm_4", alias_bfiz),
+ bfi_4 = op_alias("bfm_4", alias_bfiz),
+ ubfiz_4 = op_alias("ubfm_4", alias_bfiz),
+
+ lsl_3 = function(params, nparams)
+ if params and params[3]:byte() == 35 then
+ return alias_lslimm(params, nparams)
+ else
+ return op_template(params, "1ac02000DNMg", nparams)
+ end
+ end,
+ lsr_3 = "1ac02400DNMg|53007c00DN1w|d340fc00DN1x",
+ asr_3 = "1ac02800DNMg|13007c00DN1w|9340fc00DN1x",
+ ror_3 = "1ac02c00DNMg|13800000DNm2w|93c00000DNm2x",
+
+ clz_2 = "5ac01000DNg",
+ cls_2 = "5ac01400DNg",
+ rbit_2 = "5ac00000DNg",
+ rev_2 = "5ac00800DNw|dac00c00DNx",
+ rev16_2 = "5ac00400DNg",
+ rev32_2 = "dac00800DNx",
+
+ -- Loads and stores.
+ ["strb_*"] = "38000000DwL",
+ ["ldrb_*"] = "38400000DwL",
+ ["ldrsb_*"] = "38c00000DwL|38800000DxL",
+ ["strh_*"] = "78000000DwL",
+ ["ldrh_*"] = "78400000DwL",
+ ["ldrsh_*"] = "78c00000DwL|78800000DxL",
+ ["str_*"] = "b8000000DwL|f8000000DxL|bc000000DsL|fc000000DdL",
+ ["ldr_*"] = "18000000DwB|58000000DxB|1c000000DsB|5c000000DdB|b8400000DwL|f8400000DxL|bc400000DsL|fc400000DdL",
+ ["ldrsw_*"] = "98000000DxB|b8800000DxL",
+ -- NOTE: ldur etc. are handled by ldr et al.
+
+ ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP",
+ ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP",
+ ["ldpsw_*"] = "68400000DAxP",
+
+ -- Branches.
+ b_1 = "14000000B",
+ bl_1 = "94000000B",
+ blr_1 = "d63f0000Nx",
+ br_1 = "d61f0000Nx",
+ ret_0 = "d65f03c0",
+ ret_1 = "d65f0000Nx",
+ -- b.cond is added below.
+ cbz_2 = "34000000DBg",
+ cbnz_2 = "35000000DBg",
+ tbz_3 = "36000000DTBw|36000000DTBx",
+ tbnz_3 = "37000000DTBw|37000000DTBx",
+
+ -- Miscellaneous instructions.
+ -- TODO: hlt, hvc, smc, svc, eret, dcps[123], drps, mrs, msr
+ -- TODO: sys, sysl, ic, dc, at, tlbi
+ -- TODO: hint, yield, wfe, wfi, sev, sevl
+ -- TODO: clrex, dsb, dmb, isb
+ nop_0 = "d503201f",
+ brk_0 = "d4200000",
+ brk_1 = "d4200000W",
+
+ -- Floating point instructions.
+ fmov_2 = "1e204000DNf|1e260000DwNs|1e270000DsNw|9e660000DxNd|9e670000DdNx|1e201000DFf",
+ fabs_2 = "1e20c000DNf",
+ fneg_2 = "1e214000DNf",
+ fsqrt_2 = "1e21c000DNf",
+
+ fcvt_2 = "1e22c000DdNs|1e624000DsNd",
+
+ -- TODO: half-precision and fixed-point conversions.
+ fcvtas_2 = "1e240000DwNs|9e240000DxNs|1e640000DwNd|9e640000DxNd",
+ fcvtau_2 = "1e250000DwNs|9e250000DxNs|1e650000DwNd|9e650000DxNd",
+ fcvtms_2 = "1e300000DwNs|9e300000DxNs|1e700000DwNd|9e700000DxNd",
+ fcvtmu_2 = "1e310000DwNs|9e310000DxNs|1e710000DwNd|9e710000DxNd",
+ fcvtns_2 = "1e200000DwNs|9e200000DxNs|1e600000DwNd|9e600000DxNd",
+ fcvtnu_2 = "1e210000DwNs|9e210000DxNs|1e610000DwNd|9e610000DxNd",
+ fcvtps_2 = "1e280000DwNs|9e280000DxNs|1e680000DwNd|9e680000DxNd",
+ fcvtpu_2 = "1e290000DwNs|9e290000DxNs|1e690000DwNd|9e690000DxNd",
+ fcvtzs_2 = "1e380000DwNs|9e380000DxNs|1e780000DwNd|9e780000DxNd",
+ fcvtzu_2 = "1e390000DwNs|9e390000DxNs|1e790000DwNd|9e790000DxNd",
+
+ scvtf_2 = "1e220000DsNw|9e220000DsNx|1e620000DdNw|9e620000DdNx",
+ ucvtf_2 = "1e230000DsNw|9e230000DsNx|1e630000DdNw|9e630000DdNx",
+
+ frintn_2 = "1e244000DNf",
+ frintp_2 = "1e24c000DNf",
+ frintm_2 = "1e254000DNf",
+ frintz_2 = "1e25c000DNf",
+ frinta_2 = "1e264000DNf",
+ frintx_2 = "1e274000DNf",
+ frinti_2 = "1e27c000DNf",
+
+ fadd_3 = "1e202800DNMf",
+ fsub_3 = "1e203800DNMf",
+ fmul_3 = "1e200800DNMf",
+ fnmul_3 = "1e208800DNMf",
+ fdiv_3 = "1e201800DNMf",
+
+ fmadd_4 = "1f000000DNMAf",
+ fmsub_4 = "1f008000DNMAf",
+ fnmadd_4 = "1f200000DNMAf",
+ fnmsub_4 = "1f208000DNMAf",
+
+ fmax_3 = "1e204800DNMf",
+ fmaxnm_3 = "1e206800DNMf",
+ fmin_3 = "1e205800DNMf",
+ fminnm_3 = "1e207800DNMf",
+
+ fcmp_2 = "1e202000NMf|1e202008NZf",
+ fcmpe_2 = "1e202010NMf|1e202018NZf",
+
+ fccmp_4 = "1e200400NMVCf",
+ fccmpe_4 = "1e200410NMVCf",
+
+ fcsel_4 = "1e200c00DNMCf",
+
+ -- TODO: crc32*, aes*, sha*, pmull
+ -- TODO: SIMD instructions.
+}
+
+for cond,c in pairs(map_cond) do
+ map_op["b"..cond.."_1"] = tohex(0x54000000+c).."B"
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+local function parse_template(params, template, nparams, pos)
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n = 1
+ local rtt = {}
+
+ parse_reg_type = false
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ local q = params[n]
+ if p == "D" then
+ op = op + parse_reg(q); n = n + 1
+ elseif p == "N" then
+ op = op + shl(parse_reg(q), 5); n = n + 1
+ elseif p == "M" then
+ op = op + shl(parse_reg(q), 16); n = n + 1
+ elseif p == "A" then
+ op = op + shl(parse_reg(q), 10); n = n + 1
+ elseif p == "m" then
+ op = op + shl(parse_reg(params[n-1]), 16)
+
+ elseif p == "p" then
+ if q == "sp" then params[n] = "@x31" end
+ elseif p == "g" then
+ if parse_reg_type == "x" then
+ op = op + 0x80000000
+ elseif parse_reg_type ~= "w" then
+ werror("bad register type")
+ end
+ parse_reg_type = false
+ elseif p == "f" then
+ if parse_reg_type == "d" then
+ op = op + 0x00400000
+ elseif parse_reg_type ~= "s" then
+ werror("bad register type")
+ end
+ parse_reg_type = false
+ elseif p == "x" or p == "w" or p == "d" or p == "s" then
+ if parse_reg_type ~= p then
+ werror("register size mismatch")
+ end
+ parse_reg_type = false
+
+ elseif p == "L" then
+ op = parse_load(params, nparams, n, op)
+ elseif p == "P" then
+ op = parse_load_pair(params, nparams, n, op)
+
+ elseif p == "B" then
+ local mode, v, s = parse_label(q, false); n = n + 1
+ local m = branch_type(op)
+ waction("REL_"..mode, v+m, s, 1)
+
+ elseif p == "I" then
+ op = op + parse_imm12(q); n = n + 1
+ elseif p == "i" then
+ op = op + parse_imm13(q); n = n + 1
+ elseif p == "W" then
+ op = op + parse_imm(q, 16, 5, 0, false); n = n + 1
+ elseif p == "T" then
+ op = op + parse_imm6(q); n = n + 1
+ elseif p == "1" then
+ op = op + parse_imm(q, 6, 16, 0, false); n = n + 1
+ elseif p == "2" then
+ op = op + parse_imm(q, 6, 10, 0, false); n = n + 1
+ elseif p == "5" then
+ op = op + parse_imm(q, 5, 16, 0, false); n = n + 1
+ elseif p == "V" then
+ op = op + parse_imm(q, 4, 0, 0, false); n = n + 1
+ elseif p == "F" then
+ op = op + parse_fpimm(q); n = n + 1
+ elseif p == "Z" then
+ if q ~= "#0" and q ~= "#0.0" then werror("expected zero immediate") end
+ n = n + 1
+
+ elseif p == "S" then
+ op = op + parse_shift(q); n = n + 1
+ elseif p == "X" then
+ op = op + parse_extend(q); n = n + 1
+ elseif p == "R" then
+ op = op + parse_lslx16(q); n = n + 1
+ elseif p == "C" then
+ op = op + parse_cond(q, 0); n = n + 1
+ elseif p == "c" then
+ op = op + parse_cond(q, 1); n = n + 1
+
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+function op_template(params, template, nparams)
+ if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 3 positions.
+ if secpos+3 > maxsecpos then wflush() end
+ local pos = wpos()
+ local lpos, apos, spos = #actlist, #actargs, secpos
+
+ local ok, err
+ for t in gmatch(template, "[^|]+") do
+ ok, err = pcall(parse_template, params, t, nparams, pos)
+ if ok then return end
+ secpos = spos
+ actlist[lpos+1] = nil
+ actlist[lpos+2] = nil
+ actlist[lpos+3] = nil
+ actargs[apos+1] = nil
+ actargs[apos+2] = nil
+ actargs[apos+3] = nil
+ end
+ error(err, 0)
+end
+
+map_op[".template__"] = op_template
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/ext/opcache/jit/dynasm/dasm_mips.h b/ext/opcache/jit/dynasm/dasm_mips.h
new file mode 100644
index 0000000000..f3b43211de
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_mips.h
@@ -0,0 +1,419 @@
+/*
+** DynASM MIPS encoding engine.
+** Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH "mips"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16) - 0xff00;
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM: case DASM_IMMS:
+#ifdef DASM_CHECKS
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+#endif
+ n >>= ((ins>>10)&31);
+#ifdef DASM_CHECKS
+ if (ins & 0x8000)
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16) - 0xff00;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMMS: pos++; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16) - 0xff00;
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1);
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n);
+ if (ins & 2048)
+ n = n - (int)((char *)cp - base);
+ else
+ n = (n + (int)(size_t)base) & 0x0fffffff;
+ patchrel:
+ CK((n & 3) == 0 &&
+ ((n + ((ins & 2048) ? 0x00020000 : 0)) >>
+ ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL);
+ cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff));
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMMS:
+ cp[-1] |= ((n>>3) & 4); n &= 0x1f;
+ /* fallthrough */
+ case DASM_IMM:
+ cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/ext/opcache/jit/dynasm/dasm_mips.lua b/ext/opcache/jit/dynasm/dasm_mips.lua
new file mode 100644
index 0000000000..c8010561db
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_mips.lua
@@ -0,0 +1,1008 @@
+------------------------------------------------------------------------------
+-- DynASM MIPS32/MIPS64 module.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+local mips64 = mips64
+
+-- Module information:
+local _info = {
+ arch = mips64 and "mips64" or "mips",
+ description = "DynASM MIPS32/MIPS64 module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2016-05-24",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable = assert, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch = _s.match, _s.gmatch
+local concat, sort = table.concat, table.sort
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local tohex = bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMMS",
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(0xff000000 + w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n >= 0xff000000 then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name.
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ if s == "r29" then return "sp"
+ elseif s == "r31" then return "ra" end
+ return s
+end
+
+------------------------------------------------------------------------------
+
+-- Template strings for MIPS instructions.
+local map_op = {
+ -- First-level opcodes.
+ j_1 = "08000000J",
+ jal_1 = "0c000000J",
+ b_1 = "10000000B",
+ beqz_2 = "10000000SB",
+ beq_3 = "10000000STB",
+ bnez_2 = "14000000SB",
+ bne_3 = "14000000STB",
+ blez_2 = "18000000SB",
+ bgtz_2 = "1c000000SB",
+ addi_3 = "20000000TSI",
+ li_2 = "24000000TI",
+ addiu_3 = "24000000TSI",
+ slti_3 = "28000000TSI",
+ sltiu_3 = "2c000000TSI",
+ andi_3 = "30000000TSU",
+ lu_2 = "34000000TU",
+ ori_3 = "34000000TSU",
+ xori_3 = "38000000TSU",
+ lui_2 = "3c000000TU",
+ beqzl_2 = "50000000SB",
+ beql_3 = "50000000STB",
+ bnezl_2 = "54000000SB",
+ bnel_3 = "54000000STB",
+ blezl_2 = "58000000SB",
+ bgtzl_2 = "5c000000SB",
+ daddi_3 = mips64 and "60000000TSI",
+ daddiu_3 = mips64 and "64000000TSI",
+ ldl_2 = mips64 and "68000000TO",
+ ldr_2 = mips64 and "6c000000TO",
+ lb_2 = "80000000TO",
+ lh_2 = "84000000TO",
+ lwl_2 = "88000000TO",
+ lw_2 = "8c000000TO",
+ lbu_2 = "90000000TO",
+ lhu_2 = "94000000TO",
+ lwr_2 = "98000000TO",
+ lwu_2 = mips64 and "9c000000TO",
+ sb_2 = "a0000000TO",
+ sh_2 = "a4000000TO",
+ swl_2 = "a8000000TO",
+ sw_2 = "ac000000TO",
+ sdl_2 = mips64 and "b0000000TO",
+ sdr_2 = mips64 and "b1000000TO",
+ swr_2 = "b8000000TO",
+ cache_2 = "bc000000NO",
+ ll_2 = "c0000000TO",
+ lwc1_2 = "c4000000HO",
+ pref_2 = "cc000000NO",
+ ldc1_2 = "d4000000HO",
+ ld_2 = mips64 and "dc000000TO",
+ sc_2 = "e0000000TO",
+ swc1_2 = "e4000000HO",
+ scd_2 = mips64 and "f0000000TO",
+ sdc1_2 = "f4000000HO",
+ sd_2 = mips64 and "fc000000TO",
+
+ -- Opcode SPECIAL.
+ nop_0 = "00000000",
+ sll_3 = "00000000DTA",
+ sextw_2 = "00000000DT",
+ movf_2 = "00000001DS",
+ movf_3 = "00000001DSC",
+ movt_2 = "00010001DS",
+ movt_3 = "00010001DSC",
+ srl_3 = "00000002DTA",
+ rotr_3 = "00200002DTA",
+ sra_3 = "00000003DTA",
+ sllv_3 = "00000004DTS",
+ srlv_3 = "00000006DTS",
+ rotrv_3 = "00000046DTS",
+ drotrv_3 = mips64 and "00000056DTS",
+ srav_3 = "00000007DTS",
+ jr_1 = "00000008S",
+ jalr_1 = "0000f809S",
+ jalr_2 = "00000009DS",
+ movz_3 = "0000000aDST",
+ movn_3 = "0000000bDST",
+ syscall_0 = "0000000c",
+ syscall_1 = "0000000cY",
+ break_0 = "0000000d",
+ break_1 = "0000000dY",
+ sync_0 = "0000000f",
+ mfhi_1 = "00000010D",
+ mthi_1 = "00000011S",
+ mflo_1 = "00000012D",
+ mtlo_1 = "00000013S",
+ dsllv_3 = mips64 and "00000014DTS",
+ dsrlv_3 = mips64 and "00000016DTS",
+ dsrav_3 = mips64 and "00000017DTS",
+ mult_2 = "00000018ST",
+ multu_2 = "00000019ST",
+ div_2 = "0000001aST",
+ divu_2 = "0000001bST",
+ dmult_2 = mips64 and "0000001cST",
+ dmultu_2 = mips64 and "0000001dST",
+ ddiv_2 = mips64 and "0000001eST",
+ ddivu_2 = mips64 and "0000001fST",
+ add_3 = "00000020DST",
+ move_2 = mips64 and "00000025DS" or "00000021DS",
+ addu_3 = "00000021DST",
+ sub_3 = "00000022DST",
+ negu_2 = mips64 and "0000002fDT" or "00000023DT",
+ subu_3 = "00000023DST",
+ and_3 = "00000024DST",
+ or_3 = "00000025DST",
+ xor_3 = "00000026DST",
+ not_2 = "00000027DS",
+ nor_3 = "00000027DST",
+ slt_3 = "0000002aDST",
+ sltu_3 = "0000002bDST",
+ dadd_3 = mips64 and "0000002cDST",
+ daddu_3 = mips64 and "0000002dDST",
+ dsub_3 = mips64 and "0000002eDST",
+ dsubu_3 = mips64 and "0000002fDST",
+ tge_2 = "00000030ST",
+ tge_3 = "00000030STZ",
+ tgeu_2 = "00000031ST",
+ tgeu_3 = "00000031STZ",
+ tlt_2 = "00000032ST",
+ tlt_3 = "00000032STZ",
+ tltu_2 = "00000033ST",
+ tltu_3 = "00000033STZ",
+ teq_2 = "00000034ST",
+ teq_3 = "00000034STZ",
+ tne_2 = "00000036ST",
+ tne_3 = "00000036STZ",
+ dsll_3 = mips64 and "00000038DTa",
+ dsrl_3 = mips64 and "0000003aDTa",
+ drotr_3 = mips64 and "0020003aDTa",
+ dsra_3 = mips64 and "0000003bDTa",
+ dsll32_3 = mips64 and "0000003cDTA",
+ dsrl32_3 = mips64 and "0000003eDTA",
+ drotr32_3 = mips64 and "0020003eDTA",
+ dsra32_3 = mips64 and "0000003fDTA",
+
+ -- Opcode REGIMM.
+ bltz_2 = "04000000SB",
+ bgez_2 = "04010000SB",
+ bltzl_2 = "04020000SB",
+ bgezl_2 = "04030000SB",
+ tgei_2 = "04080000SI",
+ tgeiu_2 = "04090000SI",
+ tlti_2 = "040a0000SI",
+ tltiu_2 = "040b0000SI",
+ teqi_2 = "040c0000SI",
+ tnei_2 = "040e0000SI",
+ bltzal_2 = "04100000SB",
+ bal_1 = "04110000B",
+ bgezal_2 = "04110000SB",
+ bltzall_2 = "04120000SB",
+ bgezall_2 = "04130000SB",
+ synci_1 = "041f0000O",
+
+ -- Opcode SPECIAL2.
+ madd_2 = "70000000ST",
+ maddu_2 = "70000001ST",
+ mul_3 = "70000002DST",
+ msub_2 = "70000004ST",
+ msubu_2 = "70000005ST",
+ clz_2 = "70000020DS=",
+ clo_2 = "70000021DS=",
+ dclz_2 = mips64 and "70000024DS=",
+ dclo_2 = mips64 and "70000025DS=",
+ sdbbp_0 = "7000003f",
+ sdbbp_1 = "7000003fY",
+
+ -- Opcode SPECIAL3.
+ ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1
+ dextm_4 = mips64 and "7c000001TSAM", -- Args: pos | size-1-32
+ dextu_4 = mips64 and "7c000002TSAM", -- Args: pos-32 | size-1
+ dext_4 = mips64 and "7c000003TSAM", -- Args: pos | size-1
+ zextw_2 = mips64 and "7c00f803TS",
+ ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1
+ dinsm_4 = mips64 and "7c000005TSAM", -- Args: pos | pos+size-33
+ dinsu_4 = mips64 and "7c000006TSAM", -- Args: pos-32 | pos+size-33
+ dins_4 = mips64 and "7c000007TSAM", -- Args: pos | pos+size-1
+ wsbh_2 = "7c0000a0DT",
+ dsbh_2 = mips64 and "7c0000a4DT",
+ dshd_2 = mips64 and "7c000164DT",
+ seb_2 = "7c000420DT",
+ seh_2 = "7c000620DT",
+ rdhwr_2 = "7c00003bTD",
+
+ -- Opcode COP0.
+ mfc0_2 = "40000000TD",
+ mfc0_3 = "40000000TDW",
+ dmfc0_2 = mips64 and "40200000TD",
+ dmfc0_3 = mips64 and "40200000TDW",
+ mtc0_2 = "40800000TD",
+ mtc0_3 = "40800000TDW",
+ dmtc0_2 = mips64 and "40a00000TD",
+ dmtc0_3 = mips64 and "40a00000TDW",
+ rdpgpr_2 = "41400000DT",
+ di_0 = "41606000",
+ di_1 = "41606000T",
+ ei_0 = "41606020",
+ ei_1 = "41606020T",
+ wrpgpr_2 = "41c00000DT",
+ tlbr_0 = "42000001",
+ tlbwi_0 = "42000002",
+ tlbwr_0 = "42000006",
+ tlbp_0 = "42000008",
+ eret_0 = "42000018",
+ deret_0 = "4200001f",
+ wait_0 = "42000020",
+
+ -- Opcode COP1.
+ mfc1_2 = "44000000TG",
+ dmfc1_2 = mips64 and "44200000TG",
+ cfc1_2 = "44400000TG",
+ mfhc1_2 = "44600000TG",
+ mtc1_2 = "44800000TG",
+ dmtc1_2 = mips64 and "44a00000TG",
+ ctc1_2 = "44c00000TG",
+ mthc1_2 = "44e00000TG",
+
+ bc1f_1 = "45000000B",
+ bc1f_2 = "45000000CB",
+ bc1t_1 = "45010000B",
+ bc1t_2 = "45010000CB",
+ bc1fl_1 = "45020000B",
+ bc1fl_2 = "45020000CB",
+ bc1tl_1 = "45030000B",
+ bc1tl_2 = "45030000CB",
+
+ ["add.s_3"] = "46000000FGH",
+ ["sub.s_3"] = "46000001FGH",
+ ["mul.s_3"] = "46000002FGH",
+ ["div.s_3"] = "46000003FGH",
+ ["sqrt.s_2"] = "46000004FG",
+ ["abs.s_2"] = "46000005FG",
+ ["mov.s_2"] = "46000006FG",
+ ["neg.s_2"] = "46000007FG",
+ ["round.l.s_2"] = "46000008FG",
+ ["trunc.l.s_2"] = "46000009FG",
+ ["ceil.l.s_2"] = "4600000aFG",
+ ["floor.l.s_2"] = "4600000bFG",
+ ["round.w.s_2"] = "4600000cFG",
+ ["trunc.w.s_2"] = "4600000dFG",
+ ["ceil.w.s_2"] = "4600000eFG",
+ ["floor.w.s_2"] = "4600000fFG",
+ ["movf.s_2"] = "46000011FG",
+ ["movf.s_3"] = "46000011FGC",
+ ["movt.s_2"] = "46010011FG",
+ ["movt.s_3"] = "46010011FGC",
+ ["movz.s_3"] = "46000012FGT",
+ ["movn.s_3"] = "46000013FGT",
+ ["recip.s_2"] = "46000015FG",
+ ["rsqrt.s_2"] = "46000016FG",
+ ["cvt.d.s_2"] = "46000021FG",
+ ["cvt.w.s_2"] = "46000024FG",
+ ["cvt.l.s_2"] = "46000025FG",
+ ["cvt.ps.s_3"] = "46000026FGH",
+ ["c.f.s_2"] = "46000030GH",
+ ["c.f.s_3"] = "46000030VGH",
+ ["c.un.s_2"] = "46000031GH",
+ ["c.un.s_3"] = "46000031VGH",
+ ["c.eq.s_2"] = "46000032GH",
+ ["c.eq.s_3"] = "46000032VGH",
+ ["c.ueq.s_2"] = "46000033GH",
+ ["c.ueq.s_3"] = "46000033VGH",
+ ["c.olt.s_2"] = "46000034GH",
+ ["c.olt.s_3"] = "46000034VGH",
+ ["c.ult.s_2"] = "46000035GH",
+ ["c.ult.s_3"] = "46000035VGH",
+ ["c.ole.s_2"] = "46000036GH",
+ ["c.ole.s_3"] = "46000036VGH",
+ ["c.ule.s_2"] = "46000037GH",
+ ["c.ule.s_3"] = "46000037VGH",
+ ["c.sf.s_2"] = "46000038GH",
+ ["c.sf.s_3"] = "46000038VGH",
+ ["c.ngle.s_2"] = "46000039GH",
+ ["c.ngle.s_3"] = "46000039VGH",
+ ["c.seq.s_2"] = "4600003aGH",
+ ["c.seq.s_3"] = "4600003aVGH",
+ ["c.ngl.s_2"] = "4600003bGH",
+ ["c.ngl.s_3"] = "4600003bVGH",
+ ["c.lt.s_2"] = "4600003cGH",
+ ["c.lt.s_3"] = "4600003cVGH",
+ ["c.nge.s_2"] = "4600003dGH",
+ ["c.nge.s_3"] = "4600003dVGH",
+ ["c.le.s_2"] = "4600003eGH",
+ ["c.le.s_3"] = "4600003eVGH",
+ ["c.ngt.s_2"] = "4600003fGH",
+ ["c.ngt.s_3"] = "4600003fVGH",
+
+ ["add.d_3"] = "46200000FGH",
+ ["sub.d_3"] = "46200001FGH",
+ ["mul.d_3"] = "46200002FGH",
+ ["div.d_3"] = "46200003FGH",
+ ["sqrt.d_2"] = "46200004FG",
+ ["abs.d_2"] = "46200005FG",
+ ["mov.d_2"] = "46200006FG",
+ ["neg.d_2"] = "46200007FG",
+ ["round.l.d_2"] = "46200008FG",
+ ["trunc.l.d_2"] = "46200009FG",
+ ["ceil.l.d_2"] = "4620000aFG",
+ ["floor.l.d_2"] = "4620000bFG",
+ ["round.w.d_2"] = "4620000cFG",
+ ["trunc.w.d_2"] = "4620000dFG",
+ ["ceil.w.d_2"] = "4620000eFG",
+ ["floor.w.d_2"] = "4620000fFG",
+ ["movf.d_2"] = "46200011FG",
+ ["movf.d_3"] = "46200011FGC",
+ ["movt.d_2"] = "46210011FG",
+ ["movt.d_3"] = "46210011FGC",
+ ["movz.d_3"] = "46200012FGT",
+ ["movn.d_3"] = "46200013FGT",
+ ["recip.d_2"] = "46200015FG",
+ ["rsqrt.d_2"] = "46200016FG",
+ ["cvt.s.d_2"] = "46200020FG",
+ ["cvt.w.d_2"] = "46200024FG",
+ ["cvt.l.d_2"] = "46200025FG",
+ ["c.f.d_2"] = "46200030GH",
+ ["c.f.d_3"] = "46200030VGH",
+ ["c.un.d_2"] = "46200031GH",
+ ["c.un.d_3"] = "46200031VGH",
+ ["c.eq.d_2"] = "46200032GH",
+ ["c.eq.d_3"] = "46200032VGH",
+ ["c.ueq.d_2"] = "46200033GH",
+ ["c.ueq.d_3"] = "46200033VGH",
+ ["c.olt.d_2"] = "46200034GH",
+ ["c.olt.d_3"] = "46200034VGH",
+ ["c.ult.d_2"] = "46200035GH",
+ ["c.ult.d_3"] = "46200035VGH",
+ ["c.ole.d_2"] = "46200036GH",
+ ["c.ole.d_3"] = "46200036VGH",
+ ["c.ule.d_2"] = "46200037GH",
+ ["c.ule.d_3"] = "46200037VGH",
+ ["c.sf.d_2"] = "46200038GH",
+ ["c.sf.d_3"] = "46200038VGH",
+ ["c.ngle.d_2"] = "46200039GH",
+ ["c.ngle.d_3"] = "46200039VGH",
+ ["c.seq.d_2"] = "4620003aGH",
+ ["c.seq.d_3"] = "4620003aVGH",
+ ["c.ngl.d_2"] = "4620003bGH",
+ ["c.ngl.d_3"] = "4620003bVGH",
+ ["c.lt.d_2"] = "4620003cGH",
+ ["c.lt.d_3"] = "4620003cVGH",
+ ["c.nge.d_2"] = "4620003dGH",
+ ["c.nge.d_3"] = "4620003dVGH",
+ ["c.le.d_2"] = "4620003eGH",
+ ["c.le.d_3"] = "4620003eVGH",
+ ["c.ngt.d_2"] = "4620003fGH",
+ ["c.ngt.d_3"] = "4620003fVGH",
+
+ ["add.ps_3"] = "46c00000FGH",
+ ["sub.ps_3"] = "46c00001FGH",
+ ["mul.ps_3"] = "46c00002FGH",
+ ["abs.ps_2"] = "46c00005FG",
+ ["mov.ps_2"] = "46c00006FG",
+ ["neg.ps_2"] = "46c00007FG",
+ ["movf.ps_2"] = "46c00011FG",
+ ["movf.ps_3"] = "46c00011FGC",
+ ["movt.ps_2"] = "46c10011FG",
+ ["movt.ps_3"] = "46c10011FGC",
+ ["movz.ps_3"] = "46c00012FGT",
+ ["movn.ps_3"] = "46c00013FGT",
+ ["cvt.s.pu_2"] = "46c00020FG",
+ ["cvt.s.pl_2"] = "46c00028FG",
+ ["pll.ps_3"] = "46c0002cFGH",
+ ["plu.ps_3"] = "46c0002dFGH",
+ ["pul.ps_3"] = "46c0002eFGH",
+ ["puu.ps_3"] = "46c0002fFGH",
+ ["c.f.ps_2"] = "46c00030GH",
+ ["c.f.ps_3"] = "46c00030VGH",
+ ["c.un.ps_2"] = "46c00031GH",
+ ["c.un.ps_3"] = "46c00031VGH",
+ ["c.eq.ps_2"] = "46c00032GH",
+ ["c.eq.ps_3"] = "46c00032VGH",
+ ["c.ueq.ps_2"] = "46c00033GH",
+ ["c.ueq.ps_3"] = "46c00033VGH",
+ ["c.olt.ps_2"] = "46c00034GH",
+ ["c.olt.ps_3"] = "46c00034VGH",
+ ["c.ult.ps_2"] = "46c00035GH",
+ ["c.ult.ps_3"] = "46c00035VGH",
+ ["c.ole.ps_2"] = "46c00036GH",
+ ["c.ole.ps_3"] = "46c00036VGH",
+ ["c.ule.ps_2"] = "46c00037GH",
+ ["c.ule.ps_3"] = "46c00037VGH",
+ ["c.sf.ps_2"] = "46c00038GH",
+ ["c.sf.ps_3"] = "46c00038VGH",
+ ["c.ngle.ps_2"] = "46c00039GH",
+ ["c.ngle.ps_3"] = "46c00039VGH",
+ ["c.seq.ps_2"] = "46c0003aGH",
+ ["c.seq.ps_3"] = "46c0003aVGH",
+ ["c.ngl.ps_2"] = "46c0003bGH",
+ ["c.ngl.ps_3"] = "46c0003bVGH",
+ ["c.lt.ps_2"] = "46c0003cGH",
+ ["c.lt.ps_3"] = "46c0003cVGH",
+ ["c.nge.ps_2"] = "46c0003dGH",
+ ["c.nge.ps_3"] = "46c0003dVGH",
+ ["c.le.ps_2"] = "46c0003eGH",
+ ["c.le.ps_3"] = "46c0003eVGH",
+ ["c.ngt.ps_2"] = "46c0003fGH",
+ ["c.ngt.ps_3"] = "46c0003fVGH",
+
+ ["cvt.s.w_2"] = "46800020FG",
+ ["cvt.d.w_2"] = "46800021FG",
+
+ ["cvt.s.l_2"] = "46a00020FG",
+ ["cvt.d.l_2"] = "46a00021FG",
+
+ -- Opcode COP1X.
+ lwxc1_2 = "4c000000FX",
+ ldxc1_2 = "4c000001FX",
+ luxc1_2 = "4c000005FX",
+ swxc1_2 = "4c000008FX",
+ sdxc1_2 = "4c000009FX",
+ suxc1_2 = "4c00000dFX",
+ prefx_2 = "4c00000fMX",
+ ["alnv.ps_4"] = "4c00001eFGHS",
+ ["madd.s_4"] = "4c000020FRGH",
+ ["madd.d_4"] = "4c000021FRGH",
+ ["madd.ps_4"] = "4c000026FRGH",
+ ["msub.s_4"] = "4c000028FRGH",
+ ["msub.d_4"] = "4c000029FRGH",
+ ["msub.ps_4"] = "4c00002eFRGH",
+ ["nmadd.s_4"] = "4c000030FRGH",
+ ["nmadd.d_4"] = "4c000031FRGH",
+ ["nmadd.ps_4"] = "4c000036FRGH",
+ ["nmsub.s_4"] = "4c000038FRGH",
+ ["nmsub.d_4"] = "4c000039FRGH",
+ ["nmsub.ps_4"] = "4c00003eFRGH",
+}
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+ local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local r = match(expr, "^r([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r, tp end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_fpr(expr)
+ local r = match(expr, "^f([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_imm(imm, bits, shift, scale, signed, action)
+ local n = tonumber(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif match(imm, "^[rf]([1-3]?[0-9])$") or
+ match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then
+ werror("expected immediate operand, got register")
+ else
+ waction(action or "IMM",
+ (signed and 32768 or 0)+shl(scale, 10)+shl(bits, 5)+shift, imm)
+ return 0
+ end
+end
+
+local function parse_disp(disp)
+ local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+ if imm then
+ local r = shl(parse_gpr(reg), 21)
+ local extname = match(imm, "^extern%s+(%S+)$")
+ if extname then
+ waction("REL_EXT", map_extern[extname], nil, 1)
+ return r
+ else
+ return r + parse_imm(imm, 16, 0, 0, true)
+ end
+ end
+ local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local r, tp = parse_gpr(reg)
+ if tp then
+ waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
+ return shl(r, 21)
+ end
+ end
+ werror("bad displacement `"..disp.."'")
+end
+
+local function parse_index(idx)
+ local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$")
+ if rt then
+ rt = parse_gpr(rt)
+ rs = parse_gpr(rs)
+ return shl(rt, 16) + shl(rs, 21)
+ end
+ werror("bad index `"..idx.."'")
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+map_op[".template__"] = function(params, template, nparams)
+ if not params then return sub(template, 9) end
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n = 1
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 2 positions (ins/ext).
+ if secpos+2 > maxsecpos then wflush() end
+ local pos = wpos()
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ if p == "D" then
+ op = op + shl(parse_gpr(params[n]), 11); n = n + 1
+ elseif p == "T" then
+ op = op + shl(parse_gpr(params[n]), 16); n = n + 1
+ elseif p == "S" then
+ op = op + shl(parse_gpr(params[n]), 21); n = n + 1
+ elseif p == "F" then
+ op = op + shl(parse_fpr(params[n]), 6); n = n + 1
+ elseif p == "G" then
+ op = op + shl(parse_fpr(params[n]), 11); n = n + 1
+ elseif p == "H" then
+ op = op + shl(parse_fpr(params[n]), 16); n = n + 1
+ elseif p == "R" then
+ op = op + shl(parse_fpr(params[n]), 21); n = n + 1
+ elseif p == "I" then
+ op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
+ elseif p == "U" then
+ op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
+ elseif p == "O" then
+ op = op + parse_disp(params[n]); n = n + 1
+ elseif p == "X" then
+ op = op + parse_index(params[n]); n = n + 1
+ elseif p == "B" or p == "J" then
+ local mode, n, s = parse_label(params[n], false)
+ if p == "B" then n = n + 2048 end
+ waction("REL_"..mode, n, s, 1)
+ n = n + 1
+ elseif p == "A" then
+ op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1
+ elseif p == "a" then
+ local m = parse_imm(params[n], 6, 6, 0, false, "IMMS"); n = n + 1
+ op = op + band(m, 0x7c0) + band(shr(m, 9), 4)
+ elseif p == "M" then
+ op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1
+ elseif p == "N" then
+ op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1
+ elseif p == "C" then
+ op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1
+ elseif p == "V" then
+ op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1
+ elseif p == "W" then
+ op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1
+ elseif p == "Y" then
+ op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1
+ elseif p == "Z" then
+ op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1
+ elseif p == "=" then
+ op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo.
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/ext/opcache/jit/dynasm/dasm_mips64.lua b/ext/opcache/jit/dynasm/dasm_mips64.lua
new file mode 100644
index 0000000000..94f21921fc
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_mips64.lua
@@ -0,0 +1,12 @@
+------------------------------------------------------------------------------
+-- DynASM MIPS64 module.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+-- This module just sets 64 bit mode for the combined MIPS/MIPS64 module.
+-- All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+mips64 = true -- Using a global is an ugly, but effective solution.
+return require("dasm_mips")
diff --git a/ext/opcache/jit/dynasm/dasm_ppc.h b/ext/opcache/jit/dynasm/dasm_ppc.h
new file mode 100644
index 0000000000..3f267fb824
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_ppc.h
@@ -0,0 +1,419 @@
+/*
+** DynASM PPC/PPC64 encoding engine.
+** Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH "ppc"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. */
+enum {
+ DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT,
+ /* The following actions need a buffer position. */
+ DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG,
+ /* The following actions also have an argument. */
+ DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH,
+ DASM__MAX
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_REL 0x15000000
+#define DASM_S_UNDEF_LG 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned int *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ if (action >= DASM__MAX) {
+ ofs += 4;
+ } else {
+ int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0;
+ switch (action) {
+ case DASM_STOP: goto stop;
+ case DASM_SECTION:
+ n = (ins & 255); CK(n < D->maxsection, RANGE_SEC);
+ D->section = &D->sections[n]; goto stop;
+ case DASM_ESC: p++; ofs += 4; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break;
+ case DASM_REL_LG:
+ n = (ins & 2047) - 10; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl += 10; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ break;
+ case DASM_LABEL_LG:
+ pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC:
+ pl = D->pclabels + n; CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos;
+ }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_IMM:
+#ifdef DASM_CHECKS
+ CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I);
+#endif
+ n >>= ((ins>>10)&31);
+#ifdef DASM_CHECKS
+ if (ins & 0x8000)
+ CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I);
+ else
+ CK((n>>((ins>>5)&31)) == 0, RANGE_I);
+#endif
+ b[pos++] = n;
+ break;
+ case DASM_IMMSH:
+ CK((n >> 6) == 0, RANGE_I);
+ b[pos++] = n;
+ break;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: p++; break;
+ case DASM_REL_EXT: break;
+ case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break;
+ case DASM_REL_LG: case DASM_REL_PC: pos++; break;
+ case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break;
+ case DASM_IMM: case DASM_IMMSH: pos++; break;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0)
+#else
+#define CK(x, st) ((void)0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ char *base = (char *)buffer;
+ unsigned int *cp = (unsigned int *)buffer;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ while (1) {
+ unsigned int ins = *p++;
+ unsigned int action = (ins >> 16);
+ int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0;
+ switch (action) {
+ case DASM_STOP: case DASM_SECTION: goto stop;
+ case DASM_ESC: *cp++ = *p++; break;
+ case DASM_REL_EXT:
+ n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4;
+ goto patchrel;
+ case DASM_ALIGN:
+ ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000;
+ break;
+ case DASM_REL_LG:
+ CK(n >= 0, UNDEF_LG);
+ case DASM_REL_PC:
+ CK(n >= 0, UNDEF_PC);
+ n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base);
+ patchrel:
+ CK((n & 3) == 0 &&
+ (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >>
+ ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL);
+ cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc));
+ break;
+ case DASM_LABEL_LG:
+ ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n);
+ break;
+ case DASM_LABEL_PC: break;
+ case DASM_IMM:
+ cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31);
+ break;
+ case DASM_IMMSH:
+ cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32);
+ break;
+ default: *cp++ = ins; break;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != (char *)cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+#undef CK
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/ext/opcache/jit/dynasm/dasm_ppc.lua b/ext/opcache/jit/dynasm/dasm_ppc.lua
new file mode 100644
index 0000000000..e2f704ec18
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_ppc.lua
@@ -0,0 +1,1919 @@
+------------------------------------------------------------------------------
+-- DynASM PPC/PPC64 module.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+--
+-- Support for various extensions contributed by Caio Souza Oliveira.
+------------------------------------------------------------------------------
+
+-- Module information:
+local _info = {
+ arch = "ppc",
+ description = "DynASM PPC module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, setmetatable = assert, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local match, gmatch = _s.match, _s.gmatch
+local concat, sort = table.concat, table.sort
+local bit = bit or require("bit")
+local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift
+local tohex = bit.tohex
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ "STOP", "SECTION", "ESC", "REL_EXT",
+ "ALIGN", "REL_LG", "LABEL_LG",
+ "REL_PC", "LABEL_PC", "IMM", "IMMSH"
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number.
+local map_action = {}
+for n,name in ipairs(action_names) do
+ map_action[name] = n-1
+end
+
+-- Action list buffer.
+local actlist = {}
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+------------------------------------------------------------------------------
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ if nn == 0 then nn = 1; actlist[0] = map_action.STOP end
+ out:write("static const unsigned int ", name, "[", nn, "] = {\n")
+ for i = 1,nn-1 do
+ assert(out:write("0x", tohex(actlist[i]), ",\n"))
+ end
+ assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n"))
+end
+
+------------------------------------------------------------------------------
+
+-- Add word to action list.
+local function wputxw(n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, val, a, num)
+ local w = assert(map_action[action], "bad action name `"..action.."'")
+ wputxw(w * 0x10000 + (val or 0))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ if #actlist == actargs[1] then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true)
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped word.
+local function wputw(n)
+ if n <= 0xffffff then waction("ESC") end
+ wputxw(n)
+end
+
+-- Reserve position for word.
+local function wpos()
+ local pos = #actlist+1
+ actlist[pos] = ""
+ return pos
+end
+
+-- Store word to reserved position.
+local function wputpos(pos, n)
+ assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range")
+ actlist[pos] = n
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 20
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 2047 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=20,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=20,next_global-1 do
+ out:write(" ", prefix, t[i], ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=20,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = 0
+local map_extern_ = {}
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n > 2047 then werror("too many extern labels") end
+ next_extern = n + 1
+ t[name] = n
+ map_extern_[n] = name
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ out:write("Extern labels:\n")
+ for i=0,next_extern-1 do
+ out:write(format(" %s\n", map_extern_[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=0,next_extern-1 do
+ out:write(" \"", map_extern_[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = { sp = "r1" } -- Ext. register name -> int. name.
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for Dt... macros).
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ if s == "r1" then return "sp" end
+ return s
+end
+
+local map_cond = {
+ lt = 0, gt = 1, eq = 2, so = 3,
+ ge = 4, le = 5, ne = 6, ns = 7,
+}
+
+------------------------------------------------------------------------------
+
+local map_op, op_template
+
+local function op_alias(opname, f)
+ return function(params, nparams)
+ if not params then return "-> "..opname:sub(1, -3) end
+ f(params, nparams)
+ op_template(params, map_op[opname], nparams)
+ end
+end
+
+-- Template strings for PPC instructions.
+map_op = {
+ tdi_3 = "08000000ARI",
+ twi_3 = "0c000000ARI",
+ mulli_3 = "1c000000RRI",
+ subfic_3 = "20000000RRI",
+ cmplwi_3 = "28000000XRU",
+ cmplwi_2 = "28000000-RU",
+ cmpldi_3 = "28200000XRU",
+ cmpldi_2 = "28200000-RU",
+ cmpwi_3 = "2c000000XRI",
+ cmpwi_2 = "2c000000-RI",
+ cmpdi_3 = "2c200000XRI",
+ cmpdi_2 = "2c200000-RI",
+ addic_3 = "30000000RRI",
+ ["addic._3"] = "34000000RRI",
+ addi_3 = "38000000RR0I",
+ li_2 = "38000000RI",
+ la_2 = "38000000RD",
+ addis_3 = "3c000000RR0I",
+ lis_2 = "3c000000RI",
+ lus_2 = "3c000000RU",
+ bc_3 = "40000000AAK",
+ bcl_3 = "40000001AAK",
+ bdnz_1 = "42000000K",
+ bdz_1 = "42400000K",
+ sc_0 = "44000000",
+ b_1 = "48000000J",
+ bl_1 = "48000001J",
+ rlwimi_5 = "50000000RR~AAA.",
+ rlwinm_5 = "54000000RR~AAA.",
+ rlwnm_5 = "5c000000RR~RAA.",
+ ori_3 = "60000000RR~U",
+ nop_0 = "60000000",
+ oris_3 = "64000000RR~U",
+ xori_3 = "68000000RR~U",
+ xoris_3 = "6c000000RR~U",
+ ["andi._3"] = "70000000RR~U",
+ ["andis._3"] = "74000000RR~U",
+ lwz_2 = "80000000RD",
+ lwzu_2 = "84000000RD",
+ lbz_2 = "88000000RD",
+ lbzu_2 = "8c000000RD",
+ stw_2 = "90000000RD",
+ stwu_2 = "94000000RD",
+ stb_2 = "98000000RD",
+ stbu_2 = "9c000000RD",
+ lhz_2 = "a0000000RD",
+ lhzu_2 = "a4000000RD",
+ lha_2 = "a8000000RD",
+ lhau_2 = "ac000000RD",
+ sth_2 = "b0000000RD",
+ sthu_2 = "b4000000RD",
+ lmw_2 = "b8000000RD",
+ stmw_2 = "bc000000RD",
+ lfs_2 = "c0000000FD",
+ lfsu_2 = "c4000000FD",
+ lfd_2 = "c8000000FD",
+ lfdu_2 = "cc000000FD",
+ stfs_2 = "d0000000FD",
+ stfsu_2 = "d4000000FD",
+ stfd_2 = "d8000000FD",
+ stfdu_2 = "dc000000FD",
+ ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4.
+ ldu_2 = "e8000001RD",
+ lwa_2 = "e8000002RD",
+ std_2 = "f8000000RD",
+ stdu_2 = "f8000001RD",
+
+ subi_3 = op_alias("addi_3", function(p) p[3] = "-("..p[3]..")" end),
+ subis_3 = op_alias("addis_3", function(p) p[3] = "-("..p[3]..")" end),
+ subic_3 = op_alias("addic_3", function(p) p[3] = "-("..p[3]..")" end),
+ ["subic._3"] = op_alias("addic._3", function(p) p[3] = "-("..p[3]..")" end),
+
+ rotlwi_3 = op_alias("rlwinm_5", function(p)
+ p[4] = "0"; p[5] = "31"
+ end),
+ rotrwi_3 = op_alias("rlwinm_5", function(p)
+ p[3] = "32-("..p[3]..")"; p[4] = "0"; p[5] = "31"
+ end),
+ rotlw_3 = op_alias("rlwnm_5", function(p)
+ p[4] = "0"; p[5] = "31"
+ end),
+ slwi_3 = op_alias("rlwinm_5", function(p)
+ p[5] = "31-("..p[3]..")"; p[4] = "0"
+ end),
+ srwi_3 = op_alias("rlwinm_5", function(p)
+ p[4] = p[3]; p[3] = "32-("..p[3]..")"; p[5] = "31"
+ end),
+ clrlwi_3 = op_alias("rlwinm_5", function(p)
+ p[4] = p[3]; p[3] = "0"; p[5] = "31"
+ end),
+ clrrwi_3 = op_alias("rlwinm_5", function(p)
+ p[5] = "31-("..p[3]..")"; p[3] = "0"; p[4] = "0"
+ end),
+
+ -- Primary opcode 4:
+ mulhhwu_3 = "10000010RRR.",
+ machhwu_3 = "10000018RRR.",
+ mulhhw_3 = "10000050RRR.",
+ nmachhw_3 = "1000005cRRR.",
+ machhwsu_3 = "10000098RRR.",
+ machhws_3 = "100000d8RRR.",
+ nmachhws_3 = "100000dcRRR.",
+ mulchwu_3 = "10000110RRR.",
+ macchwu_3 = "10000118RRR.",
+ mulchw_3 = "10000150RRR.",
+ macchw_3 = "10000158RRR.",
+ nmacchw_3 = "1000015cRRR.",
+ macchwsu_3 = "10000198RRR.",
+ macchws_3 = "100001d8RRR.",
+ nmacchws_3 = "100001dcRRR.",
+ mullhw_3 = "10000350RRR.",
+ maclhw_3 = "10000358RRR.",
+ nmaclhw_3 = "1000035cRRR.",
+ maclhwsu_3 = "10000398RRR.",
+ maclhws_3 = "100003d8RRR.",
+ nmaclhws_3 = "100003dcRRR.",
+ machhwuo_3 = "10000418RRR.",
+ nmachhwo_3 = "1000045cRRR.",
+ machhwsuo_3 = "10000498RRR.",
+ machhwso_3 = "100004d8RRR.",
+ nmachhwso_3 = "100004dcRRR.",
+ macchwuo_3 = "10000518RRR.",
+ macchwo_3 = "10000558RRR.",
+ nmacchwo_3 = "1000055cRRR.",
+ macchwsuo_3 = "10000598RRR.",
+ macchwso_3 = "100005d8RRR.",
+ nmacchwso_3 = "100005dcRRR.",
+ maclhwo_3 = "10000758RRR.",
+ nmaclhwo_3 = "1000075cRRR.",
+ maclhwsuo_3 = "10000798RRR.",
+ maclhwso_3 = "100007d8RRR.",
+ nmaclhwso_3 = "100007dcRRR.",
+
+ vaddubm_3 = "10000000VVV",
+ vmaxub_3 = "10000002VVV",
+ vrlb_3 = "10000004VVV",
+ vcmpequb_3 = "10000006VVV",
+ vmuloub_3 = "10000008VVV",
+ vaddfp_3 = "1000000aVVV",
+ vmrghb_3 = "1000000cVVV",
+ vpkuhum_3 = "1000000eVVV",
+ vmhaddshs_4 = "10000020VVVV",
+ vmhraddshs_4 = "10000021VVVV",
+ vmladduhm_4 = "10000022VVVV",
+ vmsumubm_4 = "10000024VVVV",
+ vmsummbm_4 = "10000025VVVV",
+ vmsumuhm_4 = "10000026VVVV",
+ vmsumuhs_4 = "10000027VVVV",
+ vmsumshm_4 = "10000028VVVV",
+ vmsumshs_4 = "10000029VVVV",
+ vsel_4 = "1000002aVVVV",
+ vperm_4 = "1000002bVVVV",
+ vsldoi_4 = "1000002cVVVP",
+ vpermxor_4 = "1000002dVVVV",
+ vmaddfp_4 = "1000002eVVVV~",
+ vnmsubfp_4 = "1000002fVVVV~",
+ vaddeuqm_4 = "1000003cVVVV",
+ vaddecuq_4 = "1000003dVVVV",
+ vsubeuqm_4 = "1000003eVVVV",
+ vsubecuq_4 = "1000003fVVVV",
+ vadduhm_3 = "10000040VVV",
+ vmaxuh_3 = "10000042VVV",
+ vrlh_3 = "10000044VVV",
+ vcmpequh_3 = "10000046VVV",
+ vmulouh_3 = "10000048VVV",
+ vsubfp_3 = "1000004aVVV",
+ vmrghh_3 = "1000004cVVV",
+ vpkuwum_3 = "1000004eVVV",
+ vadduwm_3 = "10000080VVV",
+ vmaxuw_3 = "10000082VVV",
+ vrlw_3 = "10000084VVV",
+ vcmpequw_3 = "10000086VVV",
+ vmulouw_3 = "10000088VVV",
+ vmuluwm_3 = "10000089VVV",
+ vmrghw_3 = "1000008cVVV",
+ vpkuhus_3 = "1000008eVVV",
+ vaddudm_3 = "100000c0VVV",
+ vmaxud_3 = "100000c2VVV",
+ vrld_3 = "100000c4VVV",
+ vcmpeqfp_3 = "100000c6VVV",
+ vcmpequd_3 = "100000c7VVV",
+ vpkuwus_3 = "100000ceVVV",
+ vadduqm_3 = "10000100VVV",
+ vmaxsb_3 = "10000102VVV",
+ vslb_3 = "10000104VVV",
+ vmulosb_3 = "10000108VVV",
+ vrefp_2 = "1000010aV-V",
+ vmrglb_3 = "1000010cVVV",
+ vpkshus_3 = "1000010eVVV",
+ vaddcuq_3 = "10000140VVV",
+ vmaxsh_3 = "10000142VVV",
+ vslh_3 = "10000144VVV",
+ vmulosh_3 = "10000148VVV",
+ vrsqrtefp_2 = "1000014aV-V",
+ vmrglh_3 = "1000014cVVV",
+ vpkswus_3 = "1000014eVVV",
+ vaddcuw_3 = "10000180VVV",
+ vmaxsw_3 = "10000182VVV",
+ vslw_3 = "10000184VVV",
+ vmulosw_3 = "10000188VVV",
+ vexptefp_2 = "1000018aV-V",
+ vmrglw_3 = "1000018cVVV",
+ vpkshss_3 = "1000018eVVV",
+ vmaxsd_3 = "100001c2VVV",
+ vsl_3 = "100001c4VVV",
+ vcmpgefp_3 = "100001c6VVV",
+ vlogefp_2 = "100001caV-V",
+ vpkswss_3 = "100001ceVVV",
+ vadduhs_3 = "10000240VVV",
+ vminuh_3 = "10000242VVV",
+ vsrh_3 = "10000244VVV",
+ vcmpgtuh_3 = "10000246VVV",
+ vmuleuh_3 = "10000248VVV",
+ vrfiz_2 = "1000024aV-V",
+ vsplth_3 = "1000024cVV3",
+ vupkhsh_2 = "1000024eV-V",
+ vminuw_3 = "10000282VVV",
+ vminud_3 = "100002c2VVV",
+ vcmpgtud_3 = "100002c7VVV",
+ vrfim_2 = "100002caV-V",
+ vcmpgtsb_3 = "10000306VVV",
+ vcfux_3 = "1000030aVVA~",
+ vaddshs_3 = "10000340VVV",
+ vminsh_3 = "10000342VVV",
+ vsrah_3 = "10000344VVV",
+ vcmpgtsh_3 = "10000346VVV",
+ vmulesh_3 = "10000348VVV",
+ vcfsx_3 = "1000034aVVA~",
+ vspltish_2 = "1000034cVS",
+ vupkhpx_2 = "1000034eV-V",
+ vaddsws_3 = "10000380VVV",
+ vminsw_3 = "10000382VVV",
+ vsraw_3 = "10000384VVV",
+ vcmpgtsw_3 = "10000386VVV",
+ vmulesw_3 = "10000388VVV",
+ vctuxs_3 = "1000038aVVA~",
+ vspltisw_2 = "1000038cVS",
+ vminsd_3 = "100003c2VVV",
+ vsrad_3 = "100003c4VVV",
+ vcmpbfp_3 = "100003c6VVV",
+ vcmpgtsd_3 = "100003c7VVV",
+ vctsxs_3 = "100003caVVA~",
+ vupklpx_2 = "100003ceV-V",
+ vsububm_3 = "10000400VVV",
+ ["bcdadd._4"] = "10000401VVVy.",
+ vavgub_3 = "10000402VVV",
+ vand_3 = "10000404VVV",
+ ["vcmpequb._3"] = "10000406VVV",
+ vmaxfp_3 = "1000040aVVV",
+ vsubuhm_3 = "10000440VVV",
+ ["bcdsub._4"] = "10000441VVVy.",
+ vavguh_3 = "10000442VVV",
+ vandc_3 = "10000444VVV",
+ ["vcmpequh._3"] = "10000446VVV",
+ vminfp_3 = "1000044aVVV",
+ vpkudum_3 = "1000044eVVV",
+ vsubuwm_3 = "10000480VVV",
+ vavguw_3 = "10000482VVV",
+ vor_3 = "10000484VVV",
+ ["vcmpequw._3"] = "10000486VVV",
+ vpmsumw_3 = "10000488VVV",
+ ["vcmpeqfp._3"] = "100004c6VVV",
+ ["vcmpequd._3"] = "100004c7VVV",
+ vpkudus_3 = "100004ceVVV",
+ vavgsb_3 = "10000502VVV",
+ vavgsh_3 = "10000542VVV",
+ vorc_3 = "10000544VVV",
+ vbpermq_3 = "1000054cVVV",
+ vpksdus_3 = "1000054eVVV",
+ vavgsw_3 = "10000582VVV",
+ vsld_3 = "100005c4VVV",
+ ["vcmpgefp._3"] = "100005c6VVV",
+ vpksdss_3 = "100005ceVVV",
+ vsububs_3 = "10000600VVV",
+ mfvscr_1 = "10000604V--",
+ vsum4ubs_3 = "10000608VVV",
+ vsubuhs_3 = "10000640VVV",
+ mtvscr_1 = "10000644--V",
+ ["vcmpgtuh._3"] = "10000646VVV",
+ vsum4shs_3 = "10000648VVV",
+ vupkhsw_2 = "1000064eV-V",
+ vsubuws_3 = "10000680VVV",
+ vshasigmaw_4 = "10000682VVYp",
+ veqv_3 = "10000684VVV",
+ vsum2sws_3 = "10000688VVV",
+ vmrgow_3 = "1000068cVVV",
+ vshasigmad_4 = "100006c2VVYp",
+ vsrd_3 = "100006c4VVV",
+ ["vcmpgtud._3"] = "100006c7VVV",
+ vupklsw_2 = "100006ceV-V",
+ vupkslw_2 = "100006ceV-V",
+ vsubsbs_3 = "10000700VVV",
+ vclzb_2 = "10000702V-V",
+ vpopcntb_2 = "10000703V-V",
+ ["vcmpgtsb._3"] = "10000706VVV",
+ vsum4sbs_3 = "10000708VVV",
+ vsubshs_3 = "10000740VVV",
+ vclzh_2 = "10000742V-V",
+ vpopcnth_2 = "10000743V-V",
+ ["vcmpgtsh._3"] = "10000746VVV",
+ vsubsws_3 = "10000780VVV",
+ vclzw_2 = "10000782V-V",
+ vpopcntw_2 = "10000783V-V",
+ ["vcmpgtsw._3"] = "10000786VVV",
+ vsumsws_3 = "10000788VVV",
+ vmrgew_3 = "1000078cVVV",
+ vclzd_2 = "100007c2V-V",
+ vpopcntd_2 = "100007c3V-V",
+ ["vcmpbfp._3"] = "100007c6VVV",
+ ["vcmpgtsd._3"] = "100007c7VVV",
+
+ -- Primary opcode 19:
+ mcrf_2 = "4c000000XX",
+ isync_0 = "4c00012c",
+ crnor_3 = "4c000042CCC",
+ crnot_2 = "4c000042CC=",
+ crandc_3 = "4c000102CCC",
+ crxor_3 = "4c000182CCC",
+ crclr_1 = "4c000182C==",
+ crnand_3 = "4c0001c2CCC",
+ crand_3 = "4c000202CCC",
+ creqv_3 = "4c000242CCC",
+ crset_1 = "4c000242C==",
+ crorc_3 = "4c000342CCC",
+ cror_3 = "4c000382CCC",
+ crmove_2 = "4c000382CC=",
+ bclr_2 = "4c000020AA",
+ bclrl_2 = "4c000021AA",
+ bcctr_2 = "4c000420AA",
+ bcctrl_2 = "4c000421AA",
+ bctar_2 = "4c000460AA",
+ bctarl_2 = "4c000461AA",
+ blr_0 = "4e800020",
+ blrl_0 = "4e800021",
+ bctr_0 = "4e800420",
+ bctrl_0 = "4e800421",
+
+ -- Primary opcode 31:
+ cmpw_3 = "7c000000XRR",
+ cmpw_2 = "7c000000-RR",
+ cmpd_3 = "7c200000XRR",
+ cmpd_2 = "7c200000-RR",
+ tw_3 = "7c000008ARR",
+ lvsl_3 = "7c00000cVRR",
+ subfc_3 = "7c000010RRR.",
+ subc_3 = "7c000010RRR~.",
+ mulhdu_3 = "7c000012RRR.",
+ addc_3 = "7c000014RRR.",
+ mulhwu_3 = "7c000016RRR.",
+ isel_4 = "7c00001eRRRC",
+ isellt_3 = "7c00001eRRR",
+ iselgt_3 = "7c00005eRRR",
+ iseleq_3 = "7c00009eRRR",
+ mfcr_1 = "7c000026R",
+ mfocrf_2 = "7c100026RG",
+ mtcrf_2 = "7c000120GR",
+ mtocrf_2 = "7c100120GR",
+ lwarx_3 = "7c000028RR0R",
+ ldx_3 = "7c00002aRR0R",
+ lwzx_3 = "7c00002eRR0R",
+ slw_3 = "7c000030RR~R.",
+ cntlzw_2 = "7c000034RR~",
+ sld_3 = "7c000036RR~R.",
+ and_3 = "7c000038RR~R.",
+ cmplw_3 = "7c000040XRR",
+ cmplw_2 = "7c000040-RR",
+ cmpld_3 = "7c200040XRR",
+ cmpld_2 = "7c200040-RR",
+ lvsr_3 = "7c00004cVRR",
+ subf_3 = "7c000050RRR.",
+ sub_3 = "7c000050RRR~.",
+ lbarx_3 = "7c000068RR0R",
+ ldux_3 = "7c00006aRR0R",
+ dcbst_2 = "7c00006c-RR",
+ lwzux_3 = "7c00006eRR0R",
+ cntlzd_2 = "7c000074RR~",
+ andc_3 = "7c000078RR~R.",
+ td_3 = "7c000088ARR",
+ lvewx_3 = "7c00008eVRR",
+ mulhd_3 = "7c000092RRR.",
+ addg6s_3 = "7c000094RRR",
+ mulhw_3 = "7c000096RRR.",
+ dlmzb_3 = "7c00009cRR~R.",
+ ldarx_3 = "7c0000a8RR0R",
+ dcbf_2 = "7c0000ac-RR",
+ lbzx_3 = "7c0000aeRR0R",
+ lvx_3 = "7c0000ceVRR",
+ neg_2 = "7c0000d0RR.",
+ lharx_3 = "7c0000e8RR0R",
+ lbzux_3 = "7c0000eeRR0R",
+ popcntb_2 = "7c0000f4RR~",
+ not_2 = "7c0000f8RR~%.",
+ nor_3 = "7c0000f8RR~R.",
+ stvebx_3 = "7c00010eVRR",
+ subfe_3 = "7c000110RRR.",
+ sube_3 = "7c000110RRR~.",
+ adde_3 = "7c000114RRR.",
+ stdx_3 = "7c00012aRR0R",
+ ["stwcx._3"] = "7c00012dRR0R.",
+ stwx_3 = "7c00012eRR0R",
+ prtyw_2 = "7c000134RR~",
+ stvehx_3 = "7c00014eVRR",
+ stdux_3 = "7c00016aRR0R",
+ ["stqcx._3"] = "7c00016dR:R0R.",
+ stwux_3 = "7c00016eRR0R",
+ prtyd_2 = "7c000174RR~",
+ stvewx_3 = "7c00018eVRR",
+ subfze_2 = "7c000190RR.",
+ addze_2 = "7c000194RR.",
+ ["stdcx._3"] = "7c0001adRR0R.",
+ stbx_3 = "7c0001aeRR0R",
+ stvx_3 = "7c0001ceVRR",
+ subfme_2 = "7c0001d0RR.",
+ mulld_3 = "7c0001d2RRR.",
+ addme_2 = "7c0001d4RR.",
+ mullw_3 = "7c0001d6RRR.",
+ dcbtst_2 = "7c0001ec-RR",
+ stbux_3 = "7c0001eeRR0R",
+ bpermd_3 = "7c0001f8RR~R",
+ lvepxl_3 = "7c00020eVRR",
+ add_3 = "7c000214RRR.",
+ lqarx_3 = "7c000228R:R0R",
+ dcbt_2 = "7c00022c-RR",
+ lhzx_3 = "7c00022eRR0R",
+ cdtbcd_2 = "7c000234RR~",
+ eqv_3 = "7c000238RR~R.",
+ lvepx_3 = "7c00024eVRR",
+ eciwx_3 = "7c00026cRR0R",
+ lhzux_3 = "7c00026eRR0R",
+ cbcdtd_2 = "7c000274RR~",
+ xor_3 = "7c000278RR~R.",
+ mfspefscr_1 = "7c0082a6R",
+ mfxer_1 = "7c0102a6R",
+ mflr_1 = "7c0802a6R",
+ mfctr_1 = "7c0902a6R",
+ lwax_3 = "7c0002aaRR0R",
+ lhax_3 = "7c0002aeRR0R",
+ mftb_1 = "7c0c42e6R",
+ mftbu_1 = "7c0d42e6R",
+ lvxl_3 = "7c0002ceVRR",
+ lwaux_3 = "7c0002eaRR0R",
+ lhaux_3 = "7c0002eeRR0R",
+ popcntw_2 = "7c0002f4RR~",
+ divdeu_3 = "7c000312RRR.",
+ divweu_3 = "7c000316RRR.",
+ sthx_3 = "7c00032eRR0R",
+ orc_3 = "7c000338RR~R.",
+ ecowx_3 = "7c00036cRR0R",
+ sthux_3 = "7c00036eRR0R",
+ or_3 = "7c000378RR~R.",
+ mr_2 = "7c000378RR~%.",
+ divdu_3 = "7c000392RRR.",
+ divwu_3 = "7c000396RRR.",
+ mtspefscr_1 = "7c0083a6R",
+ mtxer_1 = "7c0103a6R",
+ mtlr_1 = "7c0803a6R",
+ mtctr_1 = "7c0903a6R",
+ dcbi_2 = "7c0003ac-RR",
+ nand_3 = "7c0003b8RR~R.",
+ dsn_2 = "7c0003c6-RR",
+ stvxl_3 = "7c0003ceVRR",
+ divd_3 = "7c0003d2RRR.",
+ divw_3 = "7c0003d6RRR.",
+ popcntd_2 = "7c0003f4RR~",
+ cmpb_3 = "7c0003f8RR~R.",
+ mcrxr_1 = "7c000400X",
+ lbdx_3 = "7c000406RRR",
+ subfco_3 = "7c000410RRR.",
+ subco_3 = "7c000410RRR~.",
+ addco_3 = "7c000414RRR.",
+ ldbrx_3 = "7c000428RR0R",
+ lswx_3 = "7c00042aRR0R",
+ lwbrx_3 = "7c00042cRR0R",
+ lfsx_3 = "7c00042eFR0R",
+ srw_3 = "7c000430RR~R.",
+ srd_3 = "7c000436RR~R.",
+ lhdx_3 = "7c000446RRR",
+ subfo_3 = "7c000450RRR.",
+ subo_3 = "7c000450RRR~.",
+ lfsux_3 = "7c00046eFR0R",
+ lwdx_3 = "7c000486RRR",
+ lswi_3 = "7c0004aaRR0A",
+ sync_0 = "7c0004ac",
+ lwsync_0 = "7c2004ac",
+ ptesync_0 = "7c4004ac",
+ lfdx_3 = "7c0004aeFR0R",
+ lddx_3 = "7c0004c6RRR",
+ nego_2 = "7c0004d0RR.",
+ lfdux_3 = "7c0004eeFR0R",
+ stbdx_3 = "7c000506RRR",
+ subfeo_3 = "7c000510RRR.",
+ subeo_3 = "7c000510RRR~.",
+ addeo_3 = "7c000514RRR.",
+ stdbrx_3 = "7c000528RR0R",
+ stswx_3 = "7c00052aRR0R",
+ stwbrx_3 = "7c00052cRR0R",
+ stfsx_3 = "7c00052eFR0R",
+ sthdx_3 = "7c000546RRR",
+ ["stbcx._3"] = "7c00056dRRR",
+ stfsux_3 = "7c00056eFR0R",
+ stwdx_3 = "7c000586RRR",
+ subfzeo_2 = "7c000590RR.",
+ addzeo_2 = "7c000594RR.",
+ stswi_3 = "7c0005aaRR0A",
+ ["sthcx._3"] = "7c0005adRRR",
+ stfdx_3 = "7c0005aeFR0R",
+ stddx_3 = "7c0005c6RRR",
+ subfmeo_2 = "7c0005d0RR.",
+ mulldo_3 = "7c0005d2RRR.",
+ addmeo_2 = "7c0005d4RR.",
+ mullwo_3 = "7c0005d6RRR.",
+ dcba_2 = "7c0005ec-RR",
+ stfdux_3 = "7c0005eeFR0R",
+ stvepxl_3 = "7c00060eVRR",
+ addo_3 = "7c000614RRR.",
+ lhbrx_3 = "7c00062cRR0R",
+ lfdpx_3 = "7c00062eF:RR",
+ sraw_3 = "7c000630RR~R.",
+ srad_3 = "7c000634RR~R.",
+ lfddx_3 = "7c000646FRR",
+ stvepx_3 = "7c00064eVRR",
+ srawi_3 = "7c000670RR~A.",
+ sradi_3 = "7c000674RR~H.",
+ eieio_0 = "7c0006ac",
+ lfiwax_3 = "7c0006aeFR0R",
+ divdeuo_3 = "7c000712RRR.",
+ divweuo_3 = "7c000716RRR.",
+ sthbrx_3 = "7c00072cRR0R",
+ stfdpx_3 = "7c00072eF:RR",
+ extsh_2 = "7c000734RR~.",
+ stfddx_3 = "7c000746FRR",
+ divdeo_3 = "7c000752RRR.",
+ divweo_3 = "7c000756RRR.",
+ extsb_2 = "7c000774RR~.",
+ divduo_3 = "7c000792RRR.",
+ divwou_3 = "7c000796RRR.",
+ icbi_2 = "7c0007ac-RR",
+ stfiwx_3 = "7c0007aeFR0R",
+ extsw_2 = "7c0007b4RR~.",
+ divdo_3 = "7c0007d2RRR.",
+ divwo_3 = "7c0007d6RRR.",
+ dcbz_2 = "7c0007ec-RR",
+
+ ["tbegin._1"] = "7c00051d1",
+ ["tbegin._0"] = "7c00051d",
+ ["tend._1"] = "7c00055dY",
+ ["tend._0"] = "7c00055d",
+ ["tendall._0"] = "7e00055d",
+ tcheck_1 = "7c00059cX",
+ ["tsr._1"] = "7c0005dd1",
+ ["tsuspend._0"] = "7c0005dd",
+ ["tresume._0"] = "7c2005dd",
+ ["tabortwc._3"] = "7c00061dARR",
+ ["tabortdc._3"] = "7c00065dARR",
+ ["tabortwci._3"] = "7c00069dARS",
+ ["tabortdci._3"] = "7c0006ddARS",
+ ["tabort._1"] = "7c00071d-R-",
+ ["treclaim._1"] = "7c00075d-R",
+ ["trechkpt._0"] = "7c0007dd",
+
+ lxsiwzx_3 = "7c000018QRR",
+ lxsiwax_3 = "7c000098QRR",
+ mfvsrd_2 = "7c000066-Rq",
+ mfvsrwz_2 = "7c0000e6-Rq",
+ stxsiwx_3 = "7c000118QRR",
+ mtvsrd_2 = "7c000166QR",
+ mtvsrwa_2 = "7c0001a6QR",
+ lxvdsx_3 = "7c000298QRR",
+ lxsspx_3 = "7c000418QRR",
+ lxsdx_3 = "7c000498QRR",
+ stxsspx_3 = "7c000518QRR",
+ stxsdx_3 = "7c000598QRR",
+ lxvw4x_3 = "7c000618QRR",
+ lxvd2x_3 = "7c000698QRR",
+ stxvw4x_3 = "7c000718QRR",
+ stxvd2x_3 = "7c000798QRR",
+
+ -- Primary opcode 30:
+ rldicl_4 = "78000000RR~HM.",
+ rldicr_4 = "78000004RR~HM.",
+ rldic_4 = "78000008RR~HM.",
+ rldimi_4 = "7800000cRR~HM.",
+ rldcl_4 = "78000010RR~RM.",
+ rldcr_4 = "78000012RR~RM.",
+
+ rotldi_3 = op_alias("rldicl_4", function(p)
+ p[4] = "0"
+ end),
+ rotrdi_3 = op_alias("rldicl_4", function(p)
+ p[3] = "64-("..p[3]..")"; p[4] = "0"
+ end),
+ rotld_3 = op_alias("rldcl_4", function(p)
+ p[4] = "0"
+ end),
+ sldi_3 = op_alias("rldicr_4", function(p)
+ p[4] = "63-("..p[3]..")"
+ end),
+ srdi_3 = op_alias("rldicl_4", function(p)
+ p[4] = p[3]; p[3] = "64-("..p[3]..")"
+ end),
+ clrldi_3 = op_alias("rldicl_4", function(p)
+ p[4] = p[3]; p[3] = "0"
+ end),
+ clrrdi_3 = op_alias("rldicr_4", function(p)
+ p[4] = "63-("..p[3]..")"; p[3] = "0"
+ end),
+
+ -- Primary opcode 56:
+ lq_2 = "e0000000R:D", -- NYI: displacement must be divisible by 8.
+
+ -- Primary opcode 57:
+ lfdp_2 = "e4000000F:D", -- NYI: displacement must be divisible by 4.
+
+ -- Primary opcode 59:
+ fdivs_3 = "ec000024FFF.",
+ fsubs_3 = "ec000028FFF.",
+ fadds_3 = "ec00002aFFF.",
+ fsqrts_2 = "ec00002cF-F.",
+ fres_2 = "ec000030F-F.",
+ fmuls_3 = "ec000032FF-F.",
+ frsqrtes_2 = "ec000034F-F.",
+ fmsubs_4 = "ec000038FFFF~.",
+ fmadds_4 = "ec00003aFFFF~.",
+ fnmsubs_4 = "ec00003cFFFF~.",
+ fnmadds_4 = "ec00003eFFFF~.",
+ fcfids_2 = "ec00069cF-F.",
+ fcfidus_2 = "ec00079cF-F.",
+
+ dadd_3 = "ec000004FFF.",
+ dqua_4 = "ec000006FFFZ.",
+ dmul_3 = "ec000044FFF.",
+ drrnd_4 = "ec000046FFFZ.",
+ dscli_3 = "ec000084FF6.",
+ dquai_4 = "ec000086SF~FZ.",
+ dscri_3 = "ec0000c4FF6.",
+ drintx_4 = "ec0000c61F~FZ.",
+ dcmpo_3 = "ec000104XFF",
+ dtstex_3 = "ec000144XFF",
+ dtstdc_3 = "ec000184XF6",
+ dtstdg_3 = "ec0001c4XF6",
+ drintn_4 = "ec0001c61F~FZ.",
+ dctdp_2 = "ec000204F-F.",
+ dctfix_2 = "ec000244F-F.",
+ ddedpd_3 = "ec000284ZF~F.",
+ dxex_2 = "ec0002c4F-F.",
+ dsub_3 = "ec000404FFF.",
+ ddiv_3 = "ec000444FFF.",
+ dcmpu_3 = "ec000504XFF",
+ dtstsf_3 = "ec000544XFF",
+ drsp_2 = "ec000604F-F.",
+ dcffix_2 = "ec000644F-F.",
+ denbcd_3 = "ec000684YF~F.",
+ diex_3 = "ec0006c4FFF.",
+
+ -- Primary opcode 60:
+ xsaddsp_3 = "f0000000QQQ",
+ xsmaddasp_3 = "f0000008QQQ",
+ xxsldwi_4 = "f0000010QQQz",
+ xsrsqrtesp_2 = "f0000028Q-Q",
+ xssqrtsp_2 = "f000002cQ-Q",
+ xxsel_4 = "f0000030QQQQ",
+ xssubsp_3 = "f0000040QQQ",
+ xsmaddmsp_3 = "f0000048QQQ",
+ xxpermdi_4 = "f0000050QQQz",
+ xsresp_2 = "f0000068Q-Q",
+ xsmulsp_3 = "f0000080QQQ",
+ xsmsubasp_3 = "f0000088QQQ",
+ xxmrghw_3 = "f0000090QQQ",
+ xsdivsp_3 = "f00000c0QQQ",
+ xsmsubmsp_3 = "f00000c8QQQ",
+ xsadddp_3 = "f0000100QQQ",
+ xsmaddadp_3 = "f0000108QQQ",
+ xscmpudp_3 = "f0000118XQQ",
+ xscvdpuxws_2 = "f0000120Q-Q",
+ xsrdpi_2 = "f0000124Q-Q",
+ xsrsqrtedp_2 = "f0000128Q-Q",
+ xssqrtdp_2 = "f000012cQ-Q",
+ xssubdp_3 = "f0000140QQQ",
+ xsmaddmdp_3 = "f0000148QQQ",
+ xscmpodp_3 = "f0000158XQQ",
+ xscvdpsxws_2 = "f0000160Q-Q",
+ xsrdpiz_2 = "f0000164Q-Q",
+ xsredp_2 = "f0000168Q-Q",
+ xsmuldp_3 = "f0000180QQQ",
+ xsmsubadp_3 = "f0000188QQQ",
+ xxmrglw_3 = "f0000190QQQ",
+ xsrdpip_2 = "f00001a4Q-Q",
+ xstsqrtdp_2 = "f00001a8X-Q",
+ xsrdpic_2 = "f00001acQ-Q",
+ xsdivdp_3 = "f00001c0QQQ",
+ xsmsubmdp_3 = "f00001c8QQQ",
+ xsrdpim_2 = "f00001e4Q-Q",
+ xstdivdp_3 = "f00001e8XQQ",
+ xvaddsp_3 = "f0000200QQQ",
+ xvmaddasp_3 = "f0000208QQQ",
+ xvcmpeqsp_3 = "f0000218QQQ",
+ xvcvspuxws_2 = "f0000220Q-Q",
+ xvrspi_2 = "f0000224Q-Q",
+ xvrsqrtesp_2 = "f0000228Q-Q",
+ xvsqrtsp_2 = "f000022cQ-Q",
+ xvsubsp_3 = "f0000240QQQ",
+ xvmaddmsp_3 = "f0000248QQQ",
+ xvcmpgtsp_3 = "f0000258QQQ",
+ xvcvspsxws_2 = "f0000260Q-Q",
+ xvrspiz_2 = "f0000264Q-Q",
+ xvresp_2 = "f0000268Q-Q",
+ xvmulsp_3 = "f0000280QQQ",
+ xvmsubasp_3 = "f0000288QQQ",
+ xxspltw_3 = "f0000290QQg~",
+ xvcmpgesp_3 = "f0000298QQQ",
+ xvcvuxwsp_2 = "f00002a0Q-Q",
+ xvrspip_2 = "f00002a4Q-Q",
+ xvtsqrtsp_2 = "f00002a8X-Q",
+ xvrspic_2 = "f00002acQ-Q",
+ xvdivsp_3 = "f00002c0QQQ",
+ xvmsubmsp_3 = "f00002c8QQQ",
+ xvcvsxwsp_2 = "f00002e0Q-Q",
+ xvrspim_2 = "f00002e4Q-Q",
+ xvtdivsp_3 = "f00002e8XQQ",
+ xvadddp_3 = "f0000300QQQ",
+ xvmaddadp_3 = "f0000308QQQ",
+ xvcmpeqdp_3 = "f0000318QQQ",
+ xvcvdpuxws_2 = "f0000320Q-Q",
+ xvrdpi_2 = "f0000324Q-Q",
+ xvrsqrtedp_2 = "f0000328Q-Q",
+ xvsqrtdp_2 = "f000032cQ-Q",
+ xvsubdp_3 = "f0000340QQQ",
+ xvmaddmdp_3 = "f0000348QQQ",
+ xvcmpgtdp_3 = "f0000358QQQ",
+ xvcvdpsxws_2 = "f0000360Q-Q",
+ xvrdpiz_2 = "f0000364Q-Q",
+ xvredp_2 = "f0000368Q-Q",
+ xvmuldp_3 = "f0000380QQQ",
+ xvmsubadp_3 = "f0000388QQQ",
+ xvcmpgedp_3 = "f0000398QQQ",
+ xvcvuxwdp_2 = "f00003a0Q-Q",
+ xvrdpip_2 = "f00003a4Q-Q",
+ xvtsqrtdp_2 = "f00003a8X-Q",
+ xvrdpic_2 = "f00003acQ-Q",
+ xvdivdp_3 = "f00003c0QQQ",
+ xvmsubmdp_3 = "f00003c8QQQ",
+ xvcvsxwdp_2 = "f00003e0Q-Q",
+ xvrdpim_2 = "f00003e4Q-Q",
+ xvtdivdp_3 = "f00003e8XQQ",
+ xsnmaddasp_3 = "f0000408QQQ",
+ xxland_3 = "f0000410QQQ",
+ xscvdpsp_2 = "f0000424Q-Q",
+ xscvdpspn_2 = "f000042cQ-Q",
+ xsnmaddmsp_3 = "f0000448QQQ",
+ xxlandc_3 = "f0000450QQQ",
+ xsrsp_2 = "f0000464Q-Q",
+ xsnmsubasp_3 = "f0000488QQQ",
+ xxlor_3 = "f0000490QQQ",
+ xscvuxdsp_2 = "f00004a0Q-Q",
+ xsnmsubmsp_3 = "f00004c8QQQ",
+ xxlxor_3 = "f00004d0QQQ",
+ xscvsxdsp_2 = "f00004e0Q-Q",
+ xsmaxdp_3 = "f0000500QQQ",
+ xsnmaddadp_3 = "f0000508QQQ",
+ xxlnor_3 = "f0000510QQQ",
+ xscvdpuxds_2 = "f0000520Q-Q",
+ xscvspdp_2 = "f0000524Q-Q",
+ xscvspdpn_2 = "f000052cQ-Q",
+ xsmindp_3 = "f0000540QQQ",
+ xsnmaddmdp_3 = "f0000548QQQ",
+ xxlorc_3 = "f0000550QQQ",
+ xscvdpsxds_2 = "f0000560Q-Q",
+ xsabsdp_2 = "f0000564Q-Q",
+ xscpsgndp_3 = "f0000580QQQ",
+ xsnmsubadp_3 = "f0000588QQQ",
+ xxlnand_3 = "f0000590QQQ",
+ xscvuxddp_2 = "f00005a0Q-Q",
+ xsnabsdp_2 = "f00005a4Q-Q",
+ xsnmsubmdp_3 = "f00005c8QQQ",
+ xxleqv_3 = "f00005d0QQQ",
+ xscvsxddp_2 = "f00005e0Q-Q",
+ xsnegdp_2 = "f00005e4Q-Q",
+ xvmaxsp_3 = "f0000600QQQ",
+ xvnmaddasp_3 = "f0000608QQQ",
+ ["xvcmpeqsp._3"] = "f0000618QQQ",
+ xvcvspuxds_2 = "f0000620Q-Q",
+ xvcvdpsp_2 = "f0000624Q-Q",
+ xvminsp_3 = "f0000640QQQ",
+ xvnmaddmsp_3 = "f0000648QQQ",
+ ["xvcmpgtsp._3"] = "f0000658QQQ",
+ xvcvspsxds_2 = "f0000660Q-Q",
+ xvabssp_2 = "f0000664Q-Q",
+ xvcpsgnsp_3 = "f0000680QQQ",
+ xvnmsubasp_3 = "f0000688QQQ",
+ ["xvcmpgesp._3"] = "f0000698QQQ",
+ xvcvuxdsp_2 = "f00006a0Q-Q",
+ xvnabssp_2 = "f00006a4Q-Q",
+ xvnmsubmsp_3 = "f00006c8QQQ",
+ xvcvsxdsp_2 = "f00006e0Q-Q",
+ xvnegsp_2 = "f00006e4Q-Q",
+ xvmaxdp_3 = "f0000700QQQ",
+ xvnmaddadp_3 = "f0000708QQQ",
+ ["xvcmpeqdp._3"] = "f0000718QQQ",
+ xvcvdpuxds_2 = "f0000720Q-Q",
+ xvcvspdp_2 = "f0000724Q-Q",
+ xvmindp_3 = "f0000740QQQ",
+ xvnmaddmdp_3 = "f0000748QQQ",
+ ["xvcmpgtdp._3"] = "f0000758QQQ",
+ xvcvdpsxds_2 = "f0000760Q-Q",
+ xvabsdp_2 = "f0000764Q-Q",
+ xvcpsgndp_3 = "f0000780QQQ",
+ xvnmsubadp_3 = "f0000788QQQ",
+ ["xvcmpgedp._3"] = "f0000798QQQ",
+ xvcvuxddp_2 = "f00007a0Q-Q",
+ xvnabsdp_2 = "f00007a4Q-Q",
+ xvnmsubmdp_3 = "f00007c8QQQ",
+ xvcvsxddp_2 = "f00007e0Q-Q",
+ xvnegdp_2 = "f00007e4Q-Q",
+
+ -- Primary opcode 61:
+ stfdp_2 = "f4000000F:D", -- NYI: displacement must be divisible by 4.
+
+ -- Primary opcode 62:
+ stq_2 = "f8000002R:D", -- NYI: displacement must be divisible by 8.
+
+ -- Primary opcode 63:
+ fdiv_3 = "fc000024FFF.",
+ fsub_3 = "fc000028FFF.",
+ fadd_3 = "fc00002aFFF.",
+ fsqrt_2 = "fc00002cF-F.",
+ fsel_4 = "fc00002eFFFF~.",
+ fre_2 = "fc000030F-F.",
+ fmul_3 = "fc000032FF-F.",
+ frsqrte_2 = "fc000034F-F.",
+ fmsub_4 = "fc000038FFFF~.",
+ fmadd_4 = "fc00003aFFFF~.",
+ fnmsub_4 = "fc00003cFFFF~.",
+ fnmadd_4 = "fc00003eFFFF~.",
+ fcmpu_3 = "fc000000XFF",
+ fcpsgn_3 = "fc000010FFF.",
+ fcmpo_3 = "fc000040XFF",
+ mtfsb1_1 = "fc00004cA",
+ fneg_2 = "fc000050F-F.",
+ mcrfs_2 = "fc000080XX",
+ mtfsb0_1 = "fc00008cA",
+ fmr_2 = "fc000090F-F.",
+ frsp_2 = "fc000018F-F.",
+ fctiw_2 = "fc00001cF-F.",
+ fctiwz_2 = "fc00001eF-F.",
+ ftdiv_2 = "fc000100X-F.",
+ fctiwu_2 = "fc00011cF-F.",
+ fctiwuz_2 = "fc00011eF-F.",
+ mtfsfi_2 = "fc00010cAA", -- NYI: upshift.
+ fnabs_2 = "fc000110F-F.",
+ ftsqrt_2 = "fc000140X-F.",
+ fabs_2 = "fc000210F-F.",
+ frin_2 = "fc000310F-F.",
+ friz_2 = "fc000350F-F.",
+ frip_2 = "fc000390F-F.",
+ frim_2 = "fc0003d0F-F.",
+ mffs_1 = "fc00048eF.",
+ -- NYI: mtfsf, mtfsb0, mtfsb1.
+ fctid_2 = "fc00065cF-F.",
+ fctidz_2 = "fc00065eF-F.",
+ fmrgow_3 = "fc00068cFFF",
+ fcfid_2 = "fc00069cF-F.",
+ fctidu_2 = "fc00075cF-F.",
+ fctiduz_2 = "fc00075eF-F.",
+ fmrgew_3 = "fc00078cFFF",
+ fcfidu_2 = "fc00079cF-F.",
+
+ daddq_3 = "fc000004F:F:F:.",
+ dquaq_4 = "fc000006F:F:F:Z.",
+ dmulq_3 = "fc000044F:F:F:.",
+ drrndq_4 = "fc000046F:F:F:Z.",
+ dscliq_3 = "fc000084F:F:6.",
+ dquaiq_4 = "fc000086SF:~F:Z.",
+ dscriq_3 = "fc0000c4F:F:6.",
+ drintxq_4 = "fc0000c61F:~F:Z.",
+ dcmpoq_3 = "fc000104XF:F:",
+ dtstexq_3 = "fc000144XF:F:",
+ dtstdcq_3 = "fc000184XF:6",
+ dtstdgq_3 = "fc0001c4XF:6",
+ drintnq_4 = "fc0001c61F:~F:Z.",
+ dctqpq_2 = "fc000204F:-F:.",
+ dctfixq_2 = "fc000244F:-F:.",
+ ddedpdq_3 = "fc000284ZF:~F:.",
+ dxexq_2 = "fc0002c4F:-F:.",
+ dsubq_3 = "fc000404F:F:F:.",
+ ddivq_3 = "fc000444F:F:F:.",
+ dcmpuq_3 = "fc000504XF:F:",
+ dtstsfq_3 = "fc000544XF:F:",
+ drdpq_2 = "fc000604F:-F:.",
+ dcffixq_2 = "fc000644F:-F:.",
+ denbcdq_3 = "fc000684YF:~F:.",
+ diexq_3 = "fc0006c4F:FF:.",
+
+ -- Primary opcode 4, SPE APU extension:
+ evaddw_3 = "10000200RRR",
+ evaddiw_3 = "10000202RAR~",
+ evsubw_3 = "10000204RRR~",
+ evsubiw_3 = "10000206RAR~",
+ evabs_2 = "10000208RR",
+ evneg_2 = "10000209RR",
+ evextsb_2 = "1000020aRR",
+ evextsh_2 = "1000020bRR",
+ evrndw_2 = "1000020cRR",
+ evcntlzw_2 = "1000020dRR",
+ evcntlsw_2 = "1000020eRR",
+ brinc_3 = "1000020fRRR",
+ evand_3 = "10000211RRR",
+ evandc_3 = "10000212RRR",
+ evxor_3 = "10000216RRR",
+ evor_3 = "10000217RRR",
+ evmr_2 = "10000217RR=",
+ evnor_3 = "10000218RRR",
+ evnot_2 = "10000218RR=",
+ eveqv_3 = "10000219RRR",
+ evorc_3 = "1000021bRRR",
+ evnand_3 = "1000021eRRR",
+ evsrwu_3 = "10000220RRR",
+ evsrws_3 = "10000221RRR",
+ evsrwiu_3 = "10000222RRA",
+ evsrwis_3 = "10000223RRA",
+ evslw_3 = "10000224RRR",
+ evslwi_3 = "10000226RRA",
+ evrlw_3 = "10000228RRR",
+ evsplati_2 = "10000229RS",
+ evrlwi_3 = "1000022aRRA",
+ evsplatfi_2 = "1000022bRS",
+ evmergehi_3 = "1000022cRRR",
+ evmergelo_3 = "1000022dRRR",
+ evcmpgtu_3 = "10000230XRR",
+ evcmpgtu_2 = "10000230-RR",
+ evcmpgts_3 = "10000231XRR",
+ evcmpgts_2 = "10000231-RR",
+ evcmpltu_3 = "10000232XRR",
+ evcmpltu_2 = "10000232-RR",
+ evcmplts_3 = "10000233XRR",
+ evcmplts_2 = "10000233-RR",
+ evcmpeq_3 = "10000234XRR",
+ evcmpeq_2 = "10000234-RR",
+ evsel_4 = "10000278RRRW",
+ evsel_3 = "10000278RRR",
+ evfsadd_3 = "10000280RRR",
+ evfssub_3 = "10000281RRR",
+ evfsabs_2 = "10000284RR",
+ evfsnabs_2 = "10000285RR",
+ evfsneg_2 = "10000286RR",
+ evfsmul_3 = "10000288RRR",
+ evfsdiv_3 = "10000289RRR",
+ evfscmpgt_3 = "1000028cXRR",
+ evfscmpgt_2 = "1000028c-RR",
+ evfscmplt_3 = "1000028dXRR",
+ evfscmplt_2 = "1000028d-RR",
+ evfscmpeq_3 = "1000028eXRR",
+ evfscmpeq_2 = "1000028e-RR",
+ evfscfui_2 = "10000290R-R",
+ evfscfsi_2 = "10000291R-R",
+ evfscfuf_2 = "10000292R-R",
+ evfscfsf_2 = "10000293R-R",
+ evfsctui_2 = "10000294R-R",
+ evfsctsi_2 = "10000295R-R",
+ evfsctuf_2 = "10000296R-R",
+ evfsctsf_2 = "10000297R-R",
+ evfsctuiz_2 = "10000298R-R",
+ evfsctsiz_2 = "1000029aR-R",
+ evfststgt_3 = "1000029cXRR",
+ evfststgt_2 = "1000029c-RR",
+ evfststlt_3 = "1000029dXRR",
+ evfststlt_2 = "1000029d-RR",
+ evfststeq_3 = "1000029eXRR",
+ evfststeq_2 = "1000029e-RR",
+ efsadd_3 = "100002c0RRR",
+ efssub_3 = "100002c1RRR",
+ efsabs_2 = "100002c4RR",
+ efsnabs_2 = "100002c5RR",
+ efsneg_2 = "100002c6RR",
+ efsmul_3 = "100002c8RRR",
+ efsdiv_3 = "100002c9RRR",
+ efscmpgt_3 = "100002ccXRR",
+ efscmpgt_2 = "100002cc-RR",
+ efscmplt_3 = "100002cdXRR",
+ efscmplt_2 = "100002cd-RR",
+ efscmpeq_3 = "100002ceXRR",
+ efscmpeq_2 = "100002ce-RR",
+ efscfd_2 = "100002cfR-R",
+ efscfui_2 = "100002d0R-R",
+ efscfsi_2 = "100002d1R-R",
+ efscfuf_2 = "100002d2R-R",
+ efscfsf_2 = "100002d3R-R",
+ efsctui_2 = "100002d4R-R",
+ efsctsi_2 = "100002d5R-R",
+ efsctuf_2 = "100002d6R-R",
+ efsctsf_2 = "100002d7R-R",
+ efsctuiz_2 = "100002d8R-R",
+ efsctsiz_2 = "100002daR-R",
+ efststgt_3 = "100002dcXRR",
+ efststgt_2 = "100002dc-RR",
+ efststlt_3 = "100002ddXRR",
+ efststlt_2 = "100002dd-RR",
+ efststeq_3 = "100002deXRR",
+ efststeq_2 = "100002de-RR",
+ efdadd_3 = "100002e0RRR",
+ efdsub_3 = "100002e1RRR",
+ efdcfuid_2 = "100002e2R-R",
+ efdcfsid_2 = "100002e3R-R",
+ efdabs_2 = "100002e4RR",
+ efdnabs_2 = "100002e5RR",
+ efdneg_2 = "100002e6RR",
+ efdmul_3 = "100002e8RRR",
+ efddiv_3 = "100002e9RRR",
+ efdctuidz_2 = "100002eaR-R",
+ efdctsidz_2 = "100002ebR-R",
+ efdcmpgt_3 = "100002ecXRR",
+ efdcmpgt_2 = "100002ec-RR",
+ efdcmplt_3 = "100002edXRR",
+ efdcmplt_2 = "100002ed-RR",
+ efdcmpeq_3 = "100002eeXRR",
+ efdcmpeq_2 = "100002ee-RR",
+ efdcfs_2 = "100002efR-R",
+ efdcfui_2 = "100002f0R-R",
+ efdcfsi_2 = "100002f1R-R",
+ efdcfuf_2 = "100002f2R-R",
+ efdcfsf_2 = "100002f3R-R",
+ efdctui_2 = "100002f4R-R",
+ efdctsi_2 = "100002f5R-R",
+ efdctuf_2 = "100002f6R-R",
+ efdctsf_2 = "100002f7R-R",
+ efdctuiz_2 = "100002f8R-R",
+ efdctsiz_2 = "100002faR-R",
+ efdtstgt_3 = "100002fcXRR",
+ efdtstgt_2 = "100002fc-RR",
+ efdtstlt_3 = "100002fdXRR",
+ efdtstlt_2 = "100002fd-RR",
+ efdtsteq_3 = "100002feXRR",
+ efdtsteq_2 = "100002fe-RR",
+ evlddx_3 = "10000300RR0R",
+ evldd_2 = "10000301R8",
+ evldwx_3 = "10000302RR0R",
+ evldw_2 = "10000303R8",
+ evldhx_3 = "10000304RR0R",
+ evldh_2 = "10000305R8",
+ evlwhex_3 = "10000310RR0R",
+ evlwhe_2 = "10000311R4",
+ evlwhoux_3 = "10000314RR0R",
+ evlwhou_2 = "10000315R4",
+ evlwhosx_3 = "10000316RR0R",
+ evlwhos_2 = "10000317R4",
+ evstddx_3 = "10000320RR0R",
+ evstdd_2 = "10000321R8",
+ evstdwx_3 = "10000322RR0R",
+ evstdw_2 = "10000323R8",
+ evstdhx_3 = "10000324RR0R",
+ evstdh_2 = "10000325R8",
+ evstwhex_3 = "10000330RR0R",
+ evstwhe_2 = "10000331R4",
+ evstwhox_3 = "10000334RR0R",
+ evstwho_2 = "10000335R4",
+ evstwwex_3 = "10000338RR0R",
+ evstwwe_2 = "10000339R4",
+ evstwwox_3 = "1000033cRR0R",
+ evstwwo_2 = "1000033dR4",
+ evmhessf_3 = "10000403RRR",
+ evmhossf_3 = "10000407RRR",
+ evmheumi_3 = "10000408RRR",
+ evmhesmi_3 = "10000409RRR",
+ evmhesmf_3 = "1000040bRRR",
+ evmhoumi_3 = "1000040cRRR",
+ evmhosmi_3 = "1000040dRRR",
+ evmhosmf_3 = "1000040fRRR",
+ evmhessfa_3 = "10000423RRR",
+ evmhossfa_3 = "10000427RRR",
+ evmheumia_3 = "10000428RRR",
+ evmhesmia_3 = "10000429RRR",
+ evmhesmfa_3 = "1000042bRRR",
+ evmhoumia_3 = "1000042cRRR",
+ evmhosmia_3 = "1000042dRRR",
+ evmhosmfa_3 = "1000042fRRR",
+ evmwhssf_3 = "10000447RRR",
+ evmwlumi_3 = "10000448RRR",
+ evmwhumi_3 = "1000044cRRR",
+ evmwhsmi_3 = "1000044dRRR",
+ evmwhsmf_3 = "1000044fRRR",
+ evmwssf_3 = "10000453RRR",
+ evmwumi_3 = "10000458RRR",
+ evmwsmi_3 = "10000459RRR",
+ evmwsmf_3 = "1000045bRRR",
+ evmwhssfa_3 = "10000467RRR",
+ evmwlumia_3 = "10000468RRR",
+ evmwhumia_3 = "1000046cRRR",
+ evmwhsmia_3 = "1000046dRRR",
+ evmwhsmfa_3 = "1000046fRRR",
+ evmwssfa_3 = "10000473RRR",
+ evmwumia_3 = "10000478RRR",
+ evmwsmia_3 = "10000479RRR",
+ evmwsmfa_3 = "1000047bRRR",
+ evmra_2 = "100004c4RR",
+ evdivws_3 = "100004c6RRR",
+ evdivwu_3 = "100004c7RRR",
+ evmwssfaa_3 = "10000553RRR",
+ evmwumiaa_3 = "10000558RRR",
+ evmwsmiaa_3 = "10000559RRR",
+ evmwsmfaa_3 = "1000055bRRR",
+ evmwssfan_3 = "100005d3RRR",
+ evmwumian_3 = "100005d8RRR",
+ evmwsmian_3 = "100005d9RRR",
+ evmwsmfan_3 = "100005dbRRR",
+ evmergehilo_3 = "1000022eRRR",
+ evmergelohi_3 = "1000022fRRR",
+ evlhhesplatx_3 = "10000308RR0R",
+ evlhhesplat_2 = "10000309R2",
+ evlhhousplatx_3 = "1000030cRR0R",
+ evlhhousplat_2 = "1000030dR2",
+ evlhhossplatx_3 = "1000030eRR0R",
+ evlhhossplat_2 = "1000030fR2",
+ evlwwsplatx_3 = "10000318RR0R",
+ evlwwsplat_2 = "10000319R4",
+ evlwhsplatx_3 = "1000031cRR0R",
+ evlwhsplat_2 = "1000031dR4",
+ evaddusiaaw_2 = "100004c0RR",
+ evaddssiaaw_2 = "100004c1RR",
+ evsubfusiaaw_2 = "100004c2RR",
+ evsubfssiaaw_2 = "100004c3RR",
+ evaddumiaaw_2 = "100004c8RR",
+ evaddsmiaaw_2 = "100004c9RR",
+ evsubfumiaaw_2 = "100004caRR",
+ evsubfsmiaaw_2 = "100004cbRR",
+ evmheusiaaw_3 = "10000500RRR",
+ evmhessiaaw_3 = "10000501RRR",
+ evmhessfaaw_3 = "10000503RRR",
+ evmhousiaaw_3 = "10000504RRR",
+ evmhossiaaw_3 = "10000505RRR",
+ evmhossfaaw_3 = "10000507RRR",
+ evmheumiaaw_3 = "10000508RRR",
+ evmhesmiaaw_3 = "10000509RRR",
+ evmhesmfaaw_3 = "1000050bRRR",
+ evmhoumiaaw_3 = "1000050cRRR",
+ evmhosmiaaw_3 = "1000050dRRR",
+ evmhosmfaaw_3 = "1000050fRRR",
+ evmhegumiaa_3 = "10000528RRR",
+ evmhegsmiaa_3 = "10000529RRR",
+ evmhegsmfaa_3 = "1000052bRRR",
+ evmhogumiaa_3 = "1000052cRRR",
+ evmhogsmiaa_3 = "1000052dRRR",
+ evmhogsmfaa_3 = "1000052fRRR",
+ evmwlusiaaw_3 = "10000540RRR",
+ evmwlssiaaw_3 = "10000541RRR",
+ evmwlumiaaw_3 = "10000548RRR",
+ evmwlsmiaaw_3 = "10000549RRR",
+ evmheusianw_3 = "10000580RRR",
+ evmhessianw_3 = "10000581RRR",
+ evmhessfanw_3 = "10000583RRR",
+ evmhousianw_3 = "10000584RRR",
+ evmhossianw_3 = "10000585RRR",
+ evmhossfanw_3 = "10000587RRR",
+ evmheumianw_3 = "10000588RRR",
+ evmhesmianw_3 = "10000589RRR",
+ evmhesmfanw_3 = "1000058bRRR",
+ evmhoumianw_3 = "1000058cRRR",
+ evmhosmianw_3 = "1000058dRRR",
+ evmhosmfanw_3 = "1000058fRRR",
+ evmhegumian_3 = "100005a8RRR",
+ evmhegsmian_3 = "100005a9RRR",
+ evmhegsmfan_3 = "100005abRRR",
+ evmhogumian_3 = "100005acRRR",
+ evmhogsmian_3 = "100005adRRR",
+ evmhogsmfan_3 = "100005afRRR",
+ evmwlusianw_3 = "100005c0RRR",
+ evmwlssianw_3 = "100005c1RRR",
+ evmwlumianw_3 = "100005c8RRR",
+ evmwlsmianw_3 = "100005c9RRR",
+
+ -- NYI: Book E instructions.
+}
+
+-- Add mnemonics for "." variants.
+do
+ local t = {}
+ for k,v in pairs(map_op) do
+ if type(v) == "string" and sub(v, -1) == "." then
+ local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2)
+ t[sub(k, 1, -3).."."..sub(k, -2)] = v2
+ end
+ end
+ for k,v in pairs(t) do
+ map_op[k] = v
+ end
+end
+
+-- Add more branch mnemonics.
+for cond,c in pairs(map_cond) do
+ local b1 = "b"..cond
+ local c1 = shl(band(c, 3), 16) + (c < 4 and 0x01000000 or 0)
+ -- bX[l]
+ map_op[b1.."_1"] = tohex(0x40800000 + c1).."K"
+ map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K"
+ map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K"
+ map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK"
+ map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK"
+ map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK"
+ -- bXlr[l]
+ map_op[b1.."lr_0"] = tohex(0x4c800020 + c1)
+ map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1)
+ map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1)
+ map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1)
+ -- bXctr[l]
+ map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X"
+ map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X"
+ map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X"
+ map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X"
+end
+
+------------------------------------------------------------------------------
+
+local function parse_gpr(expr)
+ local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ if not reg then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ expr = reg
+ end
+ local r = match(expr, "^r([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r, tp end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_fpr(expr)
+ local r = match(expr, "^f([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_vr(expr)
+ local r = match(expr, "^v([1-3]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 31 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_vs(expr)
+ local r = match(expr, "^vs([1-6]?[0-9])$")
+ if r then
+ r = tonumber(r)
+ if r <= 63 then return r end
+ end
+ werror("bad register name `"..expr.."'")
+end
+
+local function parse_cr(expr)
+ local r = match(expr, "^cr([0-7])$")
+ if r then return tonumber(r) end
+ werror("bad condition register name `"..expr.."'")
+end
+
+local function parse_cond(expr)
+ local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$")
+ if r then
+ r = tonumber(r)
+ local c = map_cond[cond]
+ if c and c < 4 then return r*4+c end
+ end
+ werror("bad condition bit name `"..expr.."'")
+end
+
+local parse_ctx = {}
+
+local loadenv = setfenv and function(s)
+ local code = loadstring(s, "")
+ if code then setfenv(code, parse_ctx) end
+ return code
+end or function(s)
+ return load(s, "", nil, parse_ctx)
+end
+
+-- Try to parse simple arithmetic, too, since some basic ops are aliases.
+local function parse_number(n)
+ local x = tonumber(n)
+ if x then return x end
+ local code = loadenv("return "..n)
+ if code then
+ local ok, y = pcall(code)
+ if ok then return y end
+ end
+ return nil
+end
+
+local function parse_imm(imm, bits, shift, scale, signed)
+ local n = parse_number(imm)
+ if n then
+ local m = sar(n, scale)
+ if shl(m, scale) == n then
+ if signed then
+ local s = sar(m, bits-1)
+ if s == 0 then return shl(m, shift)
+ elseif s == -1 then return shl(m + shl(1, bits), shift) end
+ else
+ if sar(m, bits) == 0 then return shl(m, shift) end
+ end
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif match(imm, "^[rfv]([1-3]?[0-9])$") or
+ match(imm, "^vs([1-6]?[0-9])$") or
+ match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then
+ werror("expected immediate operand, got register")
+ else
+ waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm)
+ return 0
+ end
+end
+
+local function parse_shiftmask(imm, isshift)
+ local n = parse_number(imm)
+ if n then
+ if shr(n, 6) == 0 then
+ local lsb = band(n, 31)
+ local msb = n - lsb
+ return isshift and (shl(lsb, 11)+shr(msb, 4)) or (shl(lsb, 6)+msb)
+ end
+ werror("out of range immediate `"..imm.."'")
+ elseif match(imm, "^r([1-3]?[0-9])$") or
+ match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then
+ werror("expected immediate operand, got register")
+ else
+ waction("IMMSH", isshift and 1 or 0, imm)
+ return 0;
+ end
+end
+
+local function parse_disp(disp)
+ local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+ if imm then
+ local r = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ return shl(r, 16) + parse_imm(imm, 16, 0, 0, true)
+ end
+ local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local r, tp = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ if tp then
+ waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr))
+ return shl(r, 16)
+ end
+ end
+ werror("bad displacement `"..disp.."'")
+end
+
+local function parse_u5disp(disp, scale)
+ local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$")
+ if imm then
+ local r = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ return shl(r, 16) + parse_imm(imm, 5, 11, scale, false)
+ end
+ local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$")
+ if reg and tailr ~= "" then
+ local r, tp = parse_gpr(reg)
+ if r == 0 then werror("cannot use r0 in displacement") end
+ if tp then
+ waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr))
+ return shl(r, 16)
+ end
+ end
+ werror("bad displacement `"..disp.."'")
+end
+
+local function parse_label(label, def)
+ local prefix = sub(label, 1, 2)
+ -- =>label (pc label reference)
+ if prefix == "=>" then
+ return "PC", 0, sub(label, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "LG", map_global[sub(label, 3)]
+ end
+ if def then
+ -- [1-9] (local label definition)
+ if match(label, "^[1-9]$") then
+ return "LG", 10+tonumber(label)
+ end
+ else
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(label, "^([<>])([1-9])$")
+ if dir then -- Fwd: 1-9, Bkwd: 11-19.
+ return "LG", lnum + (dir == ">" and 0 or 10)
+ end
+ -- extern label (extern label reference)
+ local extname = match(label, "^extern%s+(%S+)$")
+ if extname then
+ return "EXT", map_extern[extname]
+ end
+ end
+ werror("bad label `"..label.."'")
+end
+
+------------------------------------------------------------------------------
+
+-- Handle opcodes defined with template strings.
+op_template = function(params, template, nparams)
+ if not params then return sub(template, 9) end
+ local op = tonumber(sub(template, 1, 8), 16)
+ local n, rs = 1, 26
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 3 positions (rlwinm).
+ if secpos+3 > maxsecpos then wflush() end
+ local pos = wpos()
+
+ -- Process each character.
+ for p in gmatch(sub(template, 9), ".") do
+ if p == "R" then
+ rs = rs - 5; op = op + shl(parse_gpr(params[n]), rs); n = n + 1
+ elseif p == "F" then
+ rs = rs - 5; op = op + shl(parse_fpr(params[n]), rs); n = n + 1
+ elseif p == "V" then
+ rs = rs - 5; op = op + shl(parse_vr(params[n]), rs); n = n + 1
+ elseif p == "Q" then
+ local vs = parse_vs(params[n]); n = n + 1; rs = rs - 5
+ local sh = rs == 6 and 2 or 3 + band(shr(rs, 1), 3)
+ op = op + shl(band(vs, 31), rs) + shr(band(vs, 32), sh)
+ elseif p == "q" then
+ local vs = parse_vs(params[n]); n = n + 1
+ op = op + shl(band(vs, 31), 21) + shr(band(vs, 32), 5)
+ elseif p == "A" then
+ rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1
+ elseif p == "S" then
+ rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1
+ elseif p == "I" then
+ op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1
+ elseif p == "U" then
+ op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1
+ elseif p == "D" then
+ op = op + parse_disp(params[n]); n = n + 1
+ elseif p == "2" then
+ op = op + parse_u5disp(params[n], 1); n = n + 1
+ elseif p == "4" then
+ op = op + parse_u5disp(params[n], 2); n = n + 1
+ elseif p == "8" then
+ op = op + parse_u5disp(params[n], 3); n = n + 1
+ elseif p == "C" then
+ rs = rs - 5; op = op + shl(parse_cond(params[n]), rs); n = n + 1
+ elseif p == "X" then
+ rs = rs - 5; op = op + shl(parse_cr(params[n]), rs+2); n = n + 1
+ elseif p == "1" then
+ rs = rs - 5; op = op + parse_imm(params[n], 1, rs, 0, false); n = n + 1
+ elseif p == "g" then
+ rs = rs - 5; op = op + parse_imm(params[n], 2, rs, 0, false); n = n + 1
+ elseif p == "3" then
+ rs = rs - 5; op = op + parse_imm(params[n], 3, rs, 0, false); n = n + 1
+ elseif p == "P" then
+ rs = rs - 5; op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1
+ elseif p == "p" then
+ op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1
+ elseif p == "6" then
+ rs = rs - 6; op = op + parse_imm(params[n], 6, rs, 0, false); n = n + 1
+ elseif p == "Y" then
+ rs = rs - 5; op = op + parse_imm(params[n], 1, rs+4, 0, false); n = n + 1
+ elseif p == "y" then
+ rs = rs - 5; op = op + parse_imm(params[n], 1, rs+3, 0, false); n = n + 1
+ elseif p == "Z" then
+ rs = rs - 5; op = op + parse_imm(params[n], 2, rs+3, 0, false); n = n + 1
+ elseif p == "z" then
+ rs = rs - 5; op = op + parse_imm(params[n], 2, rs+2, 0, false); n = n + 1
+ elseif p == "W" then
+ op = op + parse_cr(params[n]); n = n + 1
+ elseif p == "G" then
+ op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1
+ elseif p == "H" then
+ op = op + parse_shiftmask(params[n], true); n = n + 1
+ elseif p == "M" then
+ op = op + parse_shiftmask(params[n], false); n = n + 1
+ elseif p == "J" or p == "K" then
+ local mode, n, s = parse_label(params[n], false)
+ if p == "K" then n = n + 2048 end
+ waction("REL_"..mode, n, s, 1)
+ n = n + 1
+ elseif p == "0" then
+ if band(shr(op, rs), 31) == 0 then werror("cannot use r0") end
+ elseif p == "=" or p == "%" then
+ local t = band(shr(op, p == "%" and rs+5 or rs), 31)
+ rs = rs - 5
+ op = op + shl(t, rs)
+ elseif p == "~" then
+ local mm = shl(31, rs)
+ local lo = band(op, mm)
+ local hi = band(op, shl(mm, 5))
+ op = op - lo - hi + shl(lo, 5) + shr(hi, 5)
+ elseif p == ":" then
+ if band(shr(op, rs), 1) ~= 0 then werror("register pair expected") end
+ elseif p == "-" then
+ rs = rs - 5
+ elseif p == "." then
+ -- Ignored.
+ else
+ assert(false)
+ end
+ end
+ wputpos(pos, op)
+end
+
+map_op[".template__"] = op_template
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_1"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr" end
+ if secpos+1 > maxsecpos then wflush() end
+ local mode, n, s = parse_label(params[1], true)
+ if mode == "EXT" then werror("bad label definition") end
+ waction("LABEL_"..mode, n, s, 1)
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+map_op[".long_*"] = function(params)
+ if not params then return "imm..." end
+ for _,p in ipairs(params) do
+ local n = tonumber(p)
+ if not n then werror("bad immediate `"..p.."'") end
+ if n < 0 then n = n + 2^32 end
+ wputw(n)
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1])
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION", num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/ext/opcache/jit/dynasm/dasm_proto.h b/ext/opcache/jit/dynasm/dasm_proto.h
new file mode 100644
index 0000000000..22a654cbfd
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_proto.h
@@ -0,0 +1,83 @@
+/*
+** DynASM encoding engine prototypes.
+** Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#ifndef _DASM_PROTO_H
+#define _DASM_PROTO_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+#define DASM_IDENT "DynASM 1.4.0"
+#define DASM_VERSION 10400 /* 1.4.0 */
+
+#ifndef Dst_DECL
+#define Dst_DECL dasm_State **Dst
+#endif
+
+#ifndef Dst_REF
+#define Dst_REF (*Dst)
+#endif
+
+#ifndef DASM_FDEF
+#define DASM_FDEF extern
+#endif
+
+#ifndef DASM_M_GROW
+#define DASM_M_GROW(ctx, t, p, sz, need) \
+ do { \
+ size_t _sz = (sz), _need = (need); \
+ if (_sz < _need) { \
+ if (_sz < 16) _sz = 16; \
+ while (_sz < _need) _sz += _sz; \
+ (p) = (t *)realloc((p), _sz); \
+ if ((p) == NULL) exit(1); \
+ (sz) = _sz; \
+ } \
+ } while(0)
+#endif
+
+#ifndef DASM_M_FREE
+#define DASM_M_FREE(ctx, p, sz) free(p)
+#endif
+
+/* Internal DynASM encoder state. */
+typedef struct dasm_State dasm_State;
+
+
+/* Initialize and free DynASM state. */
+DASM_FDEF void dasm_init(Dst_DECL, int maxsection);
+DASM_FDEF void dasm_free(Dst_DECL);
+
+/* Setup global array. Must be called before dasm_setup(). */
+DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl);
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc);
+
+/* Setup encoder. */
+DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist);
+
+/* Feed encoder with actions. Calls are generated by pre-processor. */
+DASM_FDEF void dasm_put(Dst_DECL, int start, ...);
+
+/* Link sections and return the resulting size. */
+DASM_FDEF int dasm_link(Dst_DECL, size_t *szp);
+
+/* Encode sections into buffer. */
+DASM_FDEF int dasm_encode(Dst_DECL, void *buffer);
+
+/* Get PC label offset. */
+DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc);
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch);
+#else
+#define dasm_checkstep(a, b) 0
+#endif
+
+
+#endif /* _DASM_PROTO_H */
diff --git a/ext/opcache/jit/dynasm/dasm_x64.lua b/ext/opcache/jit/dynasm/dasm_x64.lua
new file mode 100644
index 0000000000..2133355644
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_x64.lua
@@ -0,0 +1,12 @@
+------------------------------------------------------------------------------
+-- DynASM x64 module.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+-- This module just sets 64 bit mode for the combined x86/x64 module.
+-- All the interesting stuff is there.
+------------------------------------------------------------------------------
+
+x64 = true -- Using a global is an ugly, but effective solution.
+return require("dasm_x86")
diff --git a/ext/opcache/jit/dynasm/dasm_x86.h b/ext/opcache/jit/dynasm/dasm_x86.h
new file mode 100644
index 0000000000..32874b40b9
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_x86.h
@@ -0,0 +1,500 @@
+/*
+** DynASM x86 encoding engine.
+** Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+** Released under the MIT license. See dynasm.lua for full copyright notice.
+*/
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DASM_ARCH "x86"
+
+#ifndef DASM_EXTERN
+#define DASM_EXTERN(a,b,c,d) 0
+#endif
+
+/* Action definitions. DASM_STOP must be 255. */
+enum {
+ DASM_DISP = 233,
+ DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB,
+ DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC,
+ DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN,
+ DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP
+};
+
+/* Maximum number of section buffer positions for a single dasm_put() call. */
+#define DASM_MAXSECPOS 25
+
+/* DynASM encoder status codes. Action list offset or number are or'ed in. */
+#define DASM_S_OK 0x00000000
+#define DASM_S_NOMEM 0x01000000
+#define DASM_S_PHASE 0x02000000
+#define DASM_S_MATCH_SEC 0x03000000
+#define DASM_S_RANGE_I 0x11000000
+#define DASM_S_RANGE_SEC 0x12000000
+#define DASM_S_RANGE_LG 0x13000000
+#define DASM_S_RANGE_PC 0x14000000
+#define DASM_S_RANGE_VREG 0x15000000
+#define DASM_S_UNDEF_L 0x21000000
+#define DASM_S_UNDEF_PC 0x22000000
+
+/* Macros to convert positions (8 bit section + 24 bit index). */
+#define DASM_POS2IDX(pos) ((pos)&0x00ffffff)
+#define DASM_POS2BIAS(pos) ((pos)&0xff000000)
+#define DASM_SEC2POS(sec) ((sec)<<24)
+#define DASM_POS2SEC(pos) ((pos)>>24)
+#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos))
+
+/* Action list type. */
+typedef const unsigned char *dasm_ActList;
+
+/* Per-section structure. */
+typedef struct dasm_Section {
+ int *rbuf; /* Biased buffer pointer (negative section bias). */
+ int *buf; /* True buffer pointer. */
+ size_t bsize; /* Buffer size in bytes. */
+ int pos; /* Biased buffer position. */
+ int epos; /* End of biased buffer position - max single put. */
+ int ofs; /* Byte offset into section. */
+} dasm_Section;
+
+/* Core structure holding the DynASM encoding state. */
+struct dasm_State {
+ size_t psize; /* Allocated size of this structure. */
+ dasm_ActList actionlist; /* Current actionlist pointer. */
+ int *lglabels; /* Local/global chain/pos ptrs. */
+ size_t lgsize;
+ int *pclabels; /* PC label chains/pos ptrs. */
+ size_t pcsize;
+ void **globals; /* Array of globals (bias -10). */
+ dasm_Section *section; /* Pointer to active section. */
+ size_t codesize; /* Total size of all code sections. */
+ int maxsection; /* 0 <= sectionidx < maxsection. */
+ int status; /* Status code. */
+ dasm_Section sections[1]; /* All sections. Alloc-extended. */
+};
+
+/* The size of the core structure depends on the max. number of sections. */
+#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section))
+
+
+/* Initialize DynASM state. */
+void dasm_init(Dst_DECL, int maxsection)
+{
+ dasm_State *D;
+ size_t psz = 0;
+ int i;
+ Dst_REF = NULL;
+ DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection));
+ D = Dst_REF;
+ D->psize = psz;
+ D->lglabels = NULL;
+ D->lgsize = 0;
+ D->pclabels = NULL;
+ D->pcsize = 0;
+ D->globals = NULL;
+ D->maxsection = maxsection;
+ for (i = 0; i < maxsection; i++) {
+ D->sections[i].buf = NULL; /* Need this for pass3. */
+ D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i);
+ D->sections[i].bsize = 0;
+ D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */
+ }
+}
+
+/* Free DynASM state. */
+void dasm_free(Dst_DECL)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ for (i = 0; i < D->maxsection; i++)
+ if (D->sections[i].buf)
+ DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize);
+ if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize);
+ if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize);
+ DASM_M_FREE(Dst, D, D->psize);
+}
+
+/* Setup global label array. Must be called before dasm_setup(). */
+void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl)
+{
+ dasm_State *D = Dst_REF;
+ D->globals = gl - 10; /* Negative bias to compensate for locals. */
+ DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int));
+}
+
+/* Grow PC label array. Can be called after dasm_setup(), too. */
+void dasm_growpc(Dst_DECL, unsigned int maxpc)
+{
+ dasm_State *D = Dst_REF;
+ size_t osz = D->pcsize;
+ DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int));
+ memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz);
+}
+
+/* Setup encoder. */
+void dasm_setup(Dst_DECL, const void *actionlist)
+{
+ dasm_State *D = Dst_REF;
+ int i;
+ D->actionlist = (dasm_ActList)actionlist;
+ D->status = DASM_S_OK;
+ D->section = &D->sections[0];
+ memset((void *)D->lglabels, 0, D->lgsize);
+ if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize);
+ for (i = 0; i < D->maxsection; i++) {
+ D->sections[i].pos = DASM_SEC2POS(i);
+ D->sections[i].ofs = 0;
+ }
+}
+
+
+#ifdef DASM_CHECKS
+#define CK(x, st) \
+ do { if (!(x)) { \
+ D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0)
+#define CKPL(kind, st) \
+ do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \
+ D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0)
+#else
+#define CK(x, st) ((void)0)
+#define CKPL(kind, st) ((void)0)
+#endif
+
+/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */
+void dasm_put(Dst_DECL, int start, ...)
+{
+ va_list ap;
+ dasm_State *D = Dst_REF;
+ dasm_ActList p = D->actionlist + start;
+ dasm_Section *sec = D->section;
+ int pos = sec->pos, ofs = sec->ofs, mrm = -1;
+ int *b;
+
+ if (pos >= sec->epos) {
+ DASM_M_GROW(Dst, int, sec->buf, sec->bsize,
+ sec->bsize + 2*DASM_MAXSECPOS*sizeof(int));
+ sec->rbuf = sec->buf - DASM_POS2BIAS(pos);
+ sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos);
+ }
+
+ b = sec->rbuf;
+ b[pos++] = start;
+
+ va_start(ap, start);
+ while (1) {
+ int action = *p++;
+ if (action < DASM_DISP) {
+ ofs++;
+ } else if (action <= DASM_REL_A) {
+ int n = va_arg(ap, int);
+ b[pos++] = n;
+ switch (action) {
+ case DASM_DISP:
+ if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; }
+ case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob;
+ case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */
+ case DASM_IMM_D: ofs += 4; break;
+ case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob;
+ case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break;
+ case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob;
+ case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break;
+ case DASM_SPACE: p++; ofs += n; break;
+ case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */
+ case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG);
+ if (*p < 0x40 && p[1] == DASM_DISP) mrm = n;
+ if (*p < 0x20 && (n&7) == 4) ofs++;
+ switch ((*p++ >> 3) & 3) {
+ case 3: n |= b[pos-3];
+ case 2: n |= b[pos-2];
+ case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; }
+ }
+ continue;
+ }
+ mrm = -1;
+ } else {
+ int *pl, n;
+ switch (action) {
+ case DASM_REL_LG:
+ case DASM_IMM_LG:
+ n = *p++; pl = D->lglabels + n;
+ /* Bkwd rel or global. */
+ if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; }
+ pl -= 246; n = *pl;
+ if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */
+ goto linkrel;
+ case DASM_REL_PC:
+ case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
+ putrel:
+ n = *pl;
+ if (n < 0) { /* Label exists. Get label pos and store it. */
+ b[pos] = -n;
+ } else {
+ linkrel:
+ b[pos] = n; /* Else link to rel chain, anchored at label. */
+ *pl = pos;
+ }
+ pos++;
+ ofs += 4; /* Maximum offset needed. */
+ if (action == DASM_REL_LG || action == DASM_REL_PC)
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel;
+ case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC);
+ putlabel:
+ n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; }
+ *pl = -pos; /* Label exists now. */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_ALIGN:
+ ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */
+ b[pos++] = ofs; /* Store pass1 offset estimate. */
+ break;
+ case DASM_EXTERN: p += 2; ofs += 4; break;
+ case DASM_ESC: p++; ofs++; break;
+ case DASM_MARK: mrm = p[-2]; break;
+ case DASM_SECTION:
+ n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n];
+ case DASM_STOP: goto stop;
+ }
+ }
+ }
+stop:
+ va_end(ap);
+ sec->pos = pos;
+ sec->ofs = ofs;
+}
+#undef CK
+
+/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */
+int dasm_link(Dst_DECL, size_t *szp)
+{
+ dasm_State *D = Dst_REF;
+ int secnum;
+ int ofs = 0;
+
+#ifdef DASM_CHECKS
+ *szp = 0;
+ if (D->status != DASM_S_OK) return D->status;
+ {
+ int pc;
+ for (pc = 0; pc*sizeof(int) < D->pcsize; pc++)
+ if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc;
+ }
+#endif
+
+ { /* Handle globals not defined in this translation unit. */
+ int idx;
+ for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) {
+ int n = D->lglabels[idx];
+ /* Undefined label: Collapse rel chain and replace with marker (< 0). */
+ while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; }
+ }
+ }
+
+ /* Combine all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->rbuf;
+ int pos = DASM_SEC2POS(secnum);
+ int lastpos = sec->pos;
+
+ while (pos != lastpos) {
+ dasm_ActList p = D->actionlist + b[pos++];
+ while (1) {
+ int op, action = *p++;
+ switch (action) {
+ case DASM_REL_LG: p++; op = p[-3]; goto rel_pc;
+ case DASM_REL_PC: op = p[-2]; rel_pc: {
+ int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0);
+ if (shrink) { /* Shrinkable branch opcode? */
+ int lofs, lpos = b[pos];
+ if (lpos < 0) goto noshrink; /* Ext global? */
+ lofs = *DASM_POS2PTR(D, lpos);
+ if (lpos > pos) { /* Fwd label: add cumulative section offsets. */
+ int i;
+ for (i = secnum; i < DASM_POS2SEC(lpos); i++)
+ lofs += D->sections[i].ofs;
+ } else {
+ lofs -= ofs; /* Bkwd label: unfix offset. */
+ }
+ lofs -= b[pos+1]; /* Short branch ok? */
+ if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */
+ else { noshrink: shrink = 0; } /* No, cannot shrink op. */
+ }
+ b[pos+1] = shrink;
+ pos += 2;
+ break;
+ }
+ case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++;
+ case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W:
+ case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB:
+ case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break;
+ case DASM_LABEL_LG: p++;
+ case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */
+ case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */
+ case DASM_EXTERN: p += 2; break;
+ case DASM_ESC: p++; break;
+ case DASM_MARK: break;
+ case DASM_SECTION: case DASM_STOP: goto stop;
+ }
+ }
+ stop: (void)0;
+ }
+ ofs += sec->ofs; /* Next section starts right after current section. */
+ }
+
+ D->codesize = ofs; /* Total size of all code sections */
+ *szp = ofs;
+ return DASM_S_OK;
+}
+
+#define dasmb(x) *cp++ = (unsigned char)(x)
+#ifndef DASM_ALIGNED_WRITES
+typedef ZEND_SET_ALIGNED(1, unsigned short unaligned_short);
+typedef ZEND_SET_ALIGNED(1, unsigned int unaligned_int);
+#define dasmw(x) \
+ do { *((unaligned_short *)cp) = (unsigned short)(x); cp+=2; } while (0)
+#define dasmd(x) \
+ do { *((unaligned_int *)cp) = (unsigned int)(x); cp+=4; } while (0)
+#else
+#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0)
+#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0)
+#endif
+
+/* Pass 3: Encode sections. */
+int dasm_encode(Dst_DECL, void *buffer)
+{
+ dasm_State *D = Dst_REF;
+ unsigned char *base = (unsigned char *)buffer;
+ unsigned char *cp = base;
+ int secnum;
+
+ /* Encode all code sections. No support for data sections (yet). */
+ for (secnum = 0; secnum < D->maxsection; secnum++) {
+ dasm_Section *sec = D->sections + secnum;
+ int *b = sec->buf;
+ int *endb = sec->rbuf + sec->pos;
+
+ while (b != endb) {
+ dasm_ActList p = D->actionlist + *b++;
+ unsigned char *mark = NULL;
+ while (1) {
+ int action = *p++;
+ int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0;
+ switch (action) {
+ case DASM_DISP: if (!mark) mark = cp; {
+ unsigned char *mm = mark;
+ if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL;
+ if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7;
+ if (mrm != 5) { mm[-1] -= 0x80; break; } }
+ if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40;
+ }
+ case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break;
+ case DASM_IMM_DB: if (((n+128)&-256) == 0) {
+ db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb;
+ } else mark = NULL;
+ case DASM_IMM_D: wd: dasmd(n); break;
+ case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL;
+ case DASM_IMM_W: dasmw(n); break;
+ case DASM_VREG: {
+ int t = *p++;
+ unsigned char *ex = cp - (t&7);
+ if ((n & 8) && t < 0xa0) {
+ if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6);
+ n &= 7;
+ } else if (n & 0x10) {
+ if (*ex & 0x80) {
+ *ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2;
+ }
+ while (++ex < cp) ex[-1] = *ex;
+ if (mark) mark--;
+ cp--;
+ n &= 7;
+ }
+ if (t >= 0xc0) n <<= 4;
+ else if (t >= 0x40) n <<= 3;
+ else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; }
+ cp[-1] ^= n;
+ break;
+ }
+ case DASM_REL_LG: p++; if (n >= 0) goto rel_pc;
+ b++; n = (int)(ptrdiff_t)D->globals[-n];
+ case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */
+ case DASM_REL_PC: rel_pc: {
+ int shrink = *b++;
+ int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; }
+ n = *pb - ((int)(cp-base) + 4-shrink);
+ if (shrink == 0) goto wd;
+ if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb;
+ goto wb;
+ }
+ case DASM_IMM_LG:
+ p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; }
+ case DASM_IMM_PC: {
+ int *pb = DASM_POS2PTR(D, n);
+ n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base);
+ goto wd;
+ }
+ case DASM_LABEL_LG: {
+ int idx = *p++;
+ if (idx >= 10)
+ D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n));
+ break;
+ }
+ case DASM_LABEL_PC: case DASM_SETLABEL: break;
+ case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; }
+ case DASM_ALIGN:
+ n = *p++;
+ while (((cp-base) & n)) *cp++ = 0x90; /* nop */
+ break;
+ case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd;
+ case DASM_MARK: mark = cp; break;
+ case DASM_ESC: action = *p++;
+ default: *cp++ = action; break;
+ case DASM_SECTION: case DASM_STOP: goto stop;
+ }
+ }
+ stop: (void)0;
+ }
+ }
+
+ if (base + D->codesize != cp) /* Check for phase errors. */
+ return DASM_S_PHASE;
+ return DASM_S_OK;
+}
+
+/* Get PC label offset. */
+int dasm_getpclabel(Dst_DECL, unsigned int pc)
+{
+ dasm_State *D = Dst_REF;
+ if (pc*sizeof(int) < D->pcsize) {
+ int pos = D->pclabels[pc];
+ if (pos < 0) return *DASM_POS2PTR(D, -pos);
+ if (pos > 0) return -1; /* Undefined. */
+ }
+ return -2; /* Unused or out of range. */
+}
+
+#ifdef DASM_CHECKS
+/* Optional sanity checker to call between isolated encoding steps. */
+int dasm_checkstep(Dst_DECL, int secmatch)
+{
+ dasm_State *D = Dst_REF;
+ if (D->status == DASM_S_OK) {
+ int i;
+ for (i = 1; i <= 9; i++) {
+ if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; }
+ D->lglabels[i] = 0;
+ }
+ }
+ if (D->status == DASM_S_OK && secmatch >= 0 &&
+ D->section != &D->sections[secmatch])
+ D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections);
+ return D->status;
+}
+#endif
+
diff --git a/ext/opcache/jit/dynasm/dasm_x86.lua b/ext/opcache/jit/dynasm/dasm_x86.lua
new file mode 100644
index 0000000000..a5efd98fb5
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dasm_x86.lua
@@ -0,0 +1,2274 @@
+------------------------------------------------------------------------------
+-- DynASM x86/x64 module.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See dynasm.lua for full copyright notice.
+------------------------------------------------------------------------------
+
+local x64 = x64
+
+-- Module information:
+local _info = {
+ arch = x64 and "x64" or "x86",
+ description = "DynASM x86/x64 module",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ license = "MIT",
+}
+
+-- Exported glue functions for the arch-specific module.
+local _M = { _info = _info }
+
+-- Cache library functions.
+local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs
+local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable
+local _s = string
+local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char
+local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub
+local concat, sort, remove = table.concat, table.sort, table.remove
+local bit = bit or require("bit")
+local band, bxor, shl, shr = bit.band, bit.bxor, bit.lshift, bit.rshift
+
+-- Inherited tables and callbacks.
+local g_opt, g_arch
+local wline, werror, wfatal, wwarn
+
+-- Action name list.
+-- CHECK: Keep this in sync with the C code!
+local action_names = {
+ -- int arg, 1 buffer pos:
+ "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB",
+ -- action arg (1 byte), int arg, 1 buffer pos (reg/num):
+ "VREG", "SPACE",
+ -- ptrdiff_t arg, 1 buffer pos (address): !x64
+ "SETLABEL", "REL_A",
+ -- action arg (1 byte) or int arg, 2 buffer pos (link, offset):
+ "REL_LG", "REL_PC",
+ -- action arg (1 byte) or int arg, 1 buffer pos (link):
+ "IMM_LG", "IMM_PC",
+ -- action arg (1 byte) or int arg, 1 buffer pos (offset):
+ "LABEL_LG", "LABEL_PC",
+ -- action arg (1 byte), 1 buffer pos (offset):
+ "ALIGN",
+ -- action args (2 bytes), no buffer pos.
+ "EXTERN",
+ -- action arg (1 byte), no buffer pos.
+ "ESC",
+ -- no action arg, no buffer pos.
+ "MARK",
+ -- action arg (1 byte), no buffer pos, terminal action:
+ "SECTION",
+ -- no args, no buffer pos, terminal action:
+ "STOP"
+}
+
+-- Maximum number of section buffer positions for dasm_put().
+-- CHECK: Keep this in sync with the C code!
+local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines.
+
+-- Action name -> action number (dynamically generated below).
+local map_action = {}
+-- First action number. Everything below does not need to be escaped.
+local actfirst = 256-#action_names
+
+-- Action list buffer and string (only used to remove dupes).
+local actlist = {}
+local actstr = ""
+
+-- Argument list for next dasm_put(). Start with offset 0 into action list.
+local actargs = { 0 }
+
+-- Current number of section buffer positions for dasm_put().
+local secpos = 1
+
+-- VREG kind encodings, pre-shifted by 5 bits.
+local map_vreg = {
+ ["modrm.rm.m"] = 0x00,
+ ["modrm.rm.r"] = 0x20,
+ ["opcode"] = 0x20,
+ ["sib.base"] = 0x20,
+ ["sib.index"] = 0x40,
+ ["modrm.reg"] = 0x80,
+ ["vex.v"] = 0xa0,
+ ["imm.hi"] = 0xc0,
+}
+
+-- Current number of VREG actions contributing to REX/VEX shrinkage.
+local vreg_shrink_count = 0
+
+------------------------------------------------------------------------------
+
+-- Compute action numbers for action names.
+for n,name in ipairs(action_names) do
+ local num = actfirst + n - 1
+ map_action[name] = num
+end
+
+-- Dump action names and numbers.
+local function dumpactions(out)
+ out:write("DynASM encoding engine action codes:\n")
+ for n,name in ipairs(action_names) do
+ local num = map_action[name]
+ out:write(format(" %-10s %02X %d\n", name, num, num))
+ end
+ out:write("\n")
+end
+
+-- Write action list buffer as a huge static C array.
+local function writeactions(out, name)
+ local nn = #actlist
+ local last = actlist[nn] or 255
+ actlist[nn] = nil -- Remove last byte.
+ if nn == 0 then nn = 1 end
+ out:write("static const unsigned char ", name, "[", nn, "] = {\n")
+ local s = " "
+ for n,b in ipairs(actlist) do
+ s = s..b..","
+ if #s >= 75 then
+ assert(out:write(s, "\n"))
+ s = " "
+ end
+ end
+ out:write(s, last, "\n};\n\n") -- Add last byte back.
+end
+
+------------------------------------------------------------------------------
+
+-- Add byte to action list.
+local function wputxb(n)
+ assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range")
+ actlist[#actlist+1] = n
+end
+
+-- Add action to list with optional arg. Advance buffer pos, too.
+local function waction(action, a, num)
+ wputxb(assert(map_action[action], "bad action name `"..action.."'"))
+ if a then actargs[#actargs+1] = a end
+ if a or num then secpos = secpos + (num or 1) end
+end
+
+-- Optionally add a VREG action.
+local function wvreg(kind, vreg, psz, sk, defer)
+ if not vreg then return end
+ waction("VREG", vreg)
+ local b = assert(map_vreg[kind], "bad vreg kind `"..vreg.."'")
+ if b < (sk or 0) then
+ vreg_shrink_count = vreg_shrink_count + 1
+ end
+ if not defer then
+ b = b + vreg_shrink_count * 8
+ vreg_shrink_count = 0
+ end
+ wputxb(b + (psz or 0))
+end
+
+-- Add call to embedded DynASM C code.
+local function wcall(func, args)
+ wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true)
+end
+
+-- Delete duplicate action list chunks. A tad slow, but so what.
+local function dedupechunk(offset)
+ local al, as = actlist, actstr
+ local chunk = char(unpack(al, offset+1, #al))
+ local orig = find(as, chunk, 1, true)
+ if orig then
+ actargs[1] = orig-1 -- Replace with original offset.
+ for i=offset+1,#al do al[i] = nil end -- Kill dupe.
+ else
+ actstr = as..chunk
+ end
+end
+
+-- Flush action list (intervening C code or buffer pos overflow).
+local function wflush(term)
+ local offset = actargs[1]
+ if #actlist == offset then return end -- Nothing to flush.
+ if not term then waction("STOP") end -- Terminate action list.
+ dedupechunk(offset)
+ wcall("put", actargs) -- Add call to dasm_put().
+ actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put().
+ secpos = 1 -- The actionlist offset occupies a buffer position, too.
+end
+
+-- Put escaped byte.
+local function wputb(n)
+ if n >= actfirst then waction("ESC") end -- Need to escape byte.
+ wputxb(n)
+end
+
+------------------------------------------------------------------------------
+
+-- Global label name -> global label number. With auto assignment on 1st use.
+local next_global = 10
+local map_global = setmetatable({}, { __index = function(t, name)
+ if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end
+ local n = next_global
+ if n > 246 then werror("too many global labels") end
+ next_global = n + 1
+ t[name] = n
+ return n
+end})
+
+-- Dump global labels.
+local function dumpglobals(out, lvl)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("Global labels:\n")
+ for i=10,next_global-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write global label enum.
+local function writeglobals(out, prefix)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("enum {\n")
+ for i=10,next_global-1 do
+ out:write(" ", prefix, gsub(t[i], "@.*", ""), ",\n")
+ end
+ out:write(" ", prefix, "_MAX\n};\n")
+end
+
+-- Write global label names.
+local function writeglobalnames(out, name)
+ local t = {}
+ for name, n in pairs(map_global) do t[n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=10,next_global-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Extern label name -> extern label number. With auto assignment on 1st use.
+local next_extern = -1
+local map_extern = setmetatable({}, { __index = function(t, name)
+ -- No restrictions on the name for now.
+ local n = next_extern
+ if n < -256 then werror("too many extern labels") end
+ next_extern = n - 1
+ t[name] = n
+ return n
+end})
+
+-- Dump extern labels.
+local function dumpexterns(out, lvl)
+ local t = {}
+ for name, n in pairs(map_extern) do t[-n] = name end
+ out:write("Extern labels:\n")
+ for i=1,-next_extern-1 do
+ out:write(format(" %s\n", t[i]))
+ end
+ out:write("\n")
+end
+
+-- Write extern label names.
+local function writeexternnames(out, name)
+ local t = {}
+ for name, n in pairs(map_extern) do t[-n] = name end
+ out:write("static const char *const ", name, "[] = {\n")
+ for i=1,-next_extern-1 do
+ out:write(" \"", t[i], "\",\n")
+ end
+ out:write(" (const char *)0\n};\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Arch-specific maps.
+local map_archdef = {} -- Ext. register name -> int. name.
+local map_reg_rev = {} -- Int. register name -> ext. name.
+local map_reg_num = {} -- Int. register name -> register number.
+local map_reg_opsize = {} -- Int. register name -> operand size.
+local map_reg_valid_base = {} -- Int. register name -> valid base register?
+local map_reg_valid_index = {} -- Int. register name -> valid index register?
+local map_reg_needrex = {} -- Int. register name -> need rex vs. no rex.
+local reg_list = {} -- Canonical list of int. register names.
+
+local map_type = {} -- Type name -> { ctype, reg }
+local ctypenum = 0 -- Type number (for _PTx macros).
+
+local addrsize = x64 and "q" or "d" -- Size for address operands.
+
+-- Helper functions to fill register maps.
+local function mkrmap(sz, cl, names)
+ local cname = format("@%s", sz)
+ reg_list[#reg_list+1] = cname
+ map_archdef[cl] = cname
+ map_reg_rev[cname] = cl
+ map_reg_num[cname] = -1
+ map_reg_opsize[cname] = sz
+ if sz == addrsize or sz == "d" then
+ map_reg_valid_base[cname] = true
+ map_reg_valid_index[cname] = true
+ end
+ if names then
+ for n,name in ipairs(names) do
+ local iname = format("@%s%x", sz, n-1)
+ reg_list[#reg_list+1] = iname
+ map_archdef[name] = iname
+ map_reg_rev[iname] = name
+ map_reg_num[iname] = n-1
+ map_reg_opsize[iname] = sz
+ if sz == "b" and n > 4 then map_reg_needrex[iname] = false end
+ if sz == addrsize or sz == "d" then
+ map_reg_valid_base[iname] = true
+ map_reg_valid_index[iname] = true
+ end
+ end
+ end
+ for i=0,(x64 and sz ~= "f") and 15 or 7 do
+ local needrex = sz == "b" and i > 3
+ local iname = format("@%s%x%s", sz, i, needrex and "R" or "")
+ if needrex then map_reg_needrex[iname] = true end
+ local name
+ if sz == "o" or sz == "y" then name = format("%s%d", cl, i)
+ elseif sz == "f" then name = format("st%d", i)
+ else name = format("r%d%s", i, sz == addrsize and "" or sz) end
+ map_archdef[name] = iname
+ if not map_reg_rev[iname] then
+ reg_list[#reg_list+1] = iname
+ map_reg_rev[iname] = name
+ map_reg_num[iname] = i
+ map_reg_opsize[iname] = sz
+ if sz == addrsize or sz == "d" then
+ map_reg_valid_base[iname] = true
+ map_reg_valid_index[iname] = true
+ end
+ end
+ end
+ reg_list[#reg_list+1] = ""
+end
+
+-- Integer registers (qword, dword, word and byte sized).
+if x64 then
+ mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"})
+end
+mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"})
+mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"})
+mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"})
+map_reg_valid_index[map_archdef.esp] = false
+if x64 then map_reg_valid_index[map_archdef.rsp] = false end
+if x64 then map_reg_needrex[map_archdef.Rb] = true end
+map_archdef["Ra"] = "@"..addrsize
+
+-- FP registers (internally tword sized, but use "f" as operand size).
+mkrmap("f", "Rf")
+
+-- SSE registers (oword sized, but qword and dword accessible).
+mkrmap("o", "xmm")
+
+-- AVX registers (yword sized, but oword, qword and dword accessible).
+mkrmap("y", "ymm")
+
+-- Operand size prefixes to codes.
+local map_opsize = {
+ byte = "b", word = "w", dword = "d", qword = "q", oword = "o", yword = "y",
+ tword = "t", aword = addrsize,
+}
+
+-- Operand size code to number.
+local map_opsizenum = {
+ b = 1, w = 2, d = 4, q = 8, o = 16, y = 32, t = 10,
+}
+
+-- Operand size code to name.
+local map_opsizename = {
+ b = "byte", w = "word", d = "dword", q = "qword", o = "oword", y = "yword",
+ t = "tword", f = "fpword",
+}
+
+-- Valid index register scale factors.
+local map_xsc = {
+ ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3,
+}
+
+-- Condition codes.
+local map_cc = {
+ o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7,
+ s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15,
+ c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7,
+ pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15,
+}
+
+
+-- Reverse defines for registers.
+function _M.revdef(s)
+ return gsub(s, "@%w+", map_reg_rev)
+end
+
+-- Dump register names and numbers
+local function dumpregs(out)
+ out:write("Register names, sizes and internal numbers:\n")
+ for _,reg in ipairs(reg_list) do
+ if reg == "" then
+ out:write("\n")
+ else
+ local name = map_reg_rev[reg]
+ local num = map_reg_num[reg]
+ local opsize = map_opsizename[map_reg_opsize[reg]]
+ out:write(format(" %-5s %-8s %s\n", name, opsize,
+ num < 0 and "(variable)" or num))
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC).
+local function wputlabel(aprefix, imm, num)
+ if type(imm) == "number" then
+ if imm < 0 then
+ waction("EXTERN")
+ wputxb(aprefix == "IMM_" and 0 or 1)
+ imm = -imm-1
+ else
+ waction(aprefix.."LG", nil, num);
+ end
+ wputxb(imm)
+ else
+ waction(aprefix.."PC", imm, num)
+ end
+end
+
+-- Put signed byte or arg.
+local function wputsbarg(n)
+ if type(n) == "number" then
+ if n < -128 or n > 127 then
+ werror("signed immediate byte out of range")
+ end
+ if n < 0 then n = n + 256 end
+ wputb(n)
+ else waction("IMM_S", n) end
+end
+
+-- Put unsigned byte or arg.
+local function wputbarg(n)
+ if type(n) == "number" then
+ if n < 0 or n > 255 then
+ werror("unsigned immediate byte out of range")
+ end
+ wputb(n)
+ else waction("IMM_B", n) end
+end
+
+-- Put unsigned word or arg.
+local function wputwarg(n)
+ if type(n) == "number" then
+ if shr(n, 16) ~= 0 then
+ werror("unsigned immediate word out of range")
+ end
+ wputb(band(n, 255)); wputb(shr(n, 8));
+ else waction("IMM_W", n) end
+end
+
+-- Put signed or unsigned dword or arg.
+local function wputdarg(n)
+ local tn = type(n)
+ if tn == "number" then
+ wputb(band(n, 255))
+ wputb(band(shr(n, 8), 255))
+ wputb(band(shr(n, 16), 255))
+ wputb(shr(n, 24))
+ elseif tn == "table" then
+ wputlabel("IMM_", n[1], 1)
+ else
+ waction("IMM_D", n)
+ end
+end
+
+-- Put operand-size dependent number or arg (defaults to dword).
+local function wputszarg(sz, n)
+ if not sz or sz == "d" or sz == "q" then wputdarg(n)
+ elseif sz == "w" then wputwarg(n)
+ elseif sz == "b" then wputbarg(n)
+ elseif sz == "s" then wputsbarg(n)
+ else werror("bad operand size") end
+end
+
+-- Put multi-byte opcode with operand-size dependent modifications.
+local function wputop(sz, op, rex, vex, vregr, vregxb)
+ local psz, sk = 0, nil
+ if vex then
+ local tail
+ if vex.m == 1 and band(rex, 11) == 0 then
+ if x64 and vregxb then
+ sk = map_vreg["modrm.reg"]
+ else
+ wputb(0xc5)
+ tail = shl(bxor(band(rex, 4), 4), 5)
+ psz = 3
+ end
+ end
+ if not tail then
+ wputb(0xc4)
+ wputb(shl(bxor(band(rex, 7), 7), 5) + vex.m)
+ tail = shl(band(rex, 8), 4)
+ psz = 4
+ end
+ local reg, vreg = 0, nil
+ if vex.v then
+ reg = vex.v.reg
+ if not reg then werror("bad vex operand") end
+ if reg < 0 then reg = 0; vreg = vex.v.vreg end
+ end
+ if sz == "y" or vex.l then tail = tail + 4 end
+ wputb(tail + shl(bxor(reg, 15), 3) + vex.p)
+ wvreg("vex.v", vreg)
+ rex = 0
+ if op >= 256 then werror("bad vex opcode") end
+ else
+ if rex ~= 0 then
+ if not x64 then werror("bad operand size") end
+ elseif (vregr or vregxb) and x64 then
+ rex = 0x10
+ sk = map_vreg["vex.v"]
+ end
+ end
+ local r
+ if sz == "w" then wputb(102) end
+ -- Needs >32 bit numbers, but only for crc32 eax, word [ebx]
+ if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end
+ if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end
+ if op >= 65536 then
+ if rex ~= 0 then
+ local opc3 = band(op, 0xffff00)
+ if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then
+ wputb(64 + band(rex, 15)); rex = 0; psz = 2
+ end
+ end
+ wputb(shr(op, 16)); op = band(op, 0xffff); psz = psz + 1
+ end
+ if op >= 256 then
+ local b = shr(op, 8)
+ if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0; psz = 2 end
+ wputb(b); op = band(op, 255); psz = psz + 1
+ end
+ if rex ~= 0 then wputb(64 + band(rex, 15)); psz = 2 end
+ if sz == "b" then op = op - 1 end
+ wputb(op)
+ return psz, sk
+end
+
+-- Put ModRM or SIB formatted byte.
+local function wputmodrm(m, s, rm, vs, vrm)
+ assert(m < 4 and s < 16 and rm < 16, "bad modrm operands")
+ wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7))
+end
+
+-- Put ModRM/SIB plus optional displacement.
+local function wputmrmsib(t, imark, s, vsreg, psz, sk)
+ local vreg, vxreg
+ local reg, xreg = t.reg, t.xreg
+ if reg and reg < 0 then reg = 0; vreg = t.vreg end
+ if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end
+ if s < 0 then s = 0 end
+
+ -- Register mode.
+ if sub(t.mode, 1, 1) == "r" then
+ wputmodrm(3, s, reg)
+ wvreg("modrm.reg", vsreg, psz+1, sk, vreg)
+ wvreg("modrm.rm.r", vreg, psz+1, sk)
+ return
+ end
+
+ local disp = t.disp
+ local tdisp = type(disp)
+ -- No base register?
+ if not reg then
+ local riprel = false
+ if xreg then
+ -- Indexed mode with index register only.
+ -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp)
+ wputmodrm(0, s, 4)
+ if imark == "I" then waction("MARK") end
+ wvreg("modrm.reg", vsreg, psz+1, sk, vxreg)
+ wputmodrm(t.xsc, xreg, 5)
+ wvreg("sib.index", vxreg, psz+2, sk)
+ else
+ -- Pure 32 bit displacement.
+ if x64 and tdisp ~= "table" then
+ wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp)
+ wvreg("modrm.reg", vsreg, psz+1, sk)
+ if imark == "I" then waction("MARK") end
+ wputmodrm(0, 4, 5)
+ else
+ riprel = x64
+ wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp)
+ wvreg("modrm.reg", vsreg, psz+1, sk)
+ if imark == "I" then waction("MARK") end
+ end
+ end
+ if riprel then -- Emit rip-relative displacement.
+ if match("UWSiI", imark) then
+ werror("NYI: rip-relative displacement followed by immediate")
+ end
+ -- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f.
+ wputlabel("REL_", disp[1], 2)
+ else
+ wputdarg(disp)
+ end
+ return
+ end
+
+ local m
+ if tdisp == "number" then -- Check displacement size at assembly time.
+ if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too)
+ if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0]
+ elseif disp >= -128 and disp <= 127 then m = 1
+ else m = 2 end
+ elseif tdisp == "table" then
+ m = 2
+ end
+
+ -- Index register present or esp as base register: need SIB encoding.
+ if xreg or band(reg, 7) == 4 then
+ wputmodrm(m or 2, s, 4) -- ModRM.
+ if m == nil or imark == "I" then waction("MARK") end
+ wvreg("modrm.reg", vsreg, psz+1, sk, vxreg or vreg)
+ wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB.
+ wvreg("sib.index", vxreg, psz+2, sk, vreg)
+ wvreg("sib.base", vreg, psz+2, sk)
+ else
+ wputmodrm(m or 2, s, reg) -- ModRM.
+ if (imark == "I" and (m == 1 or m == 2)) or
+ (m == nil and (vsreg or vreg)) then waction("MARK") end
+ wvreg("modrm.reg", vsreg, psz+1, sk, vreg)
+ wvreg("modrm.rm.m", vreg, psz+1, sk)
+ end
+
+ -- Put displacement.
+ if m == 1 then wputsbarg(disp)
+ elseif m == 2 then wputdarg(disp)
+ elseif m == nil then waction("DISP", disp) end
+end
+
+------------------------------------------------------------------------------
+
+-- Return human-readable operand mode string.
+local function opmodestr(op, args)
+ local m = {}
+ for i=1,#args do
+ local a = args[i]
+ m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?")
+ end
+ return op.." "..concat(m, ",")
+end
+
+-- Convert number to valid integer or nil.
+local function toint(expr)
+ local n = tonumber(expr)
+ if n then
+ if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then
+ werror("bad integer number `"..expr.."'")
+ end
+ return n
+ end
+end
+
+-- Parse immediate expression.
+local function immexpr(expr)
+ -- &expr (pointer)
+ if sub(expr, 1, 1) == "&" then
+ return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2))
+ end
+
+ local prefix = sub(expr, 1, 2)
+ -- =>expr (pc label reference)
+ if prefix == "=>" then
+ return "iJ", sub(expr, 3)
+ end
+ -- ->name (global label reference)
+ if prefix == "->" then
+ return "iJ", map_global[sub(expr, 3)]
+ end
+
+ -- [<>][1-9] (local label reference)
+ local dir, lnum = match(expr, "^([<>])([1-9])$")
+ if dir then -- Fwd: 247-255, Bkwd: 1-9.
+ return "iJ", lnum + (dir == ">" and 246 or 0)
+ end
+
+ local extname = match(expr, "^extern%s+(%S+)$")
+ if extname then
+ return "iJ", map_extern[extname]
+ end
+
+ -- expr (interpreted as immediate)
+ return "iI", expr
+end
+
+-- Parse displacement expression: +-num, +-expr, +-opsize*num
+local function dispexpr(expr)
+ local disp = expr == "" and 0 or toint(expr)
+ if disp then return disp end
+ local c, dispt = match(expr, "^([+-])%s*(.+)$")
+ if c == "+" then
+ expr = dispt
+ elseif not c then
+ werror("bad displacement expression `"..expr.."'")
+ end
+ local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$")
+ local ops, imm = map_opsize[opsize], toint(tailops)
+ if ops and imm then
+ if c == "-" then imm = -imm end
+ return imm*map_opsizenum[ops]
+ end
+ local mode, iexpr = immexpr(dispt)
+ if mode == "iJ" then
+ if c == "-" then werror("cannot invert label reference") end
+ return { iexpr }
+ end
+ return expr -- Need to return original signed expression.
+end
+
+-- Parse register or type expression.
+local function rtexpr(expr)
+ if not expr then return end
+ local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$")
+ local tp = map_type[tname or expr]
+ if tp then
+ local reg = ovreg or tp.reg
+ local rnum = map_reg_num[reg]
+ if not rnum then
+ werror("type `"..(tname or expr).."' needs a register override")
+ end
+ if not map_reg_valid_base[reg] then
+ werror("bad base register override `"..(map_reg_rev[reg] or reg).."'")
+ end
+ return reg, rnum, tp
+ end
+ return expr, map_reg_num[expr]
+end
+
+-- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }.
+local function parseoperand(param)
+ local t = {}
+
+ local expr = param
+ local opsize, tailops = match(param, "^(%w+)%s*(.+)$")
+ if opsize then
+ t.opsize = map_opsize[opsize]
+ if t.opsize then expr = tailops end
+ end
+
+ local br = match(expr, "^%[%s*(.-)%s*%]$")
+ repeat
+ if br then
+ t.mode = "xm"
+
+ -- [disp]
+ t.disp = toint(br)
+ if t.disp then
+ t.mode = x64 and "xm" or "xmO"
+ break
+ end
+
+ -- [reg...]
+ local tp
+ local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$")
+ reg, t.reg, tp = rtexpr(reg)
+ if not t.reg then
+ -- [expr]
+ t.mode = x64 and "xm" or "xmO"
+ t.disp = dispexpr("+"..br)
+ break
+ end
+
+ if t.reg == -1 then
+ t.vreg, tailr = match(tailr, "^(%b())(.*)$")
+ if not t.vreg then werror("bad variable register expression") end
+ end
+
+ -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr]
+ local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$")
+ if xsc then
+ if not map_reg_valid_index[reg] then
+ werror("bad index register `"..map_reg_rev[reg].."'")
+ end
+ t.xsc = map_xsc[xsc]
+ t.xreg = t.reg
+ t.vxreg = t.vreg
+ t.reg = nil
+ t.vreg = nil
+ t.disp = dispexpr(tailsc)
+ break
+ end
+ if not map_reg_valid_base[reg] then
+ werror("bad base register `"..map_reg_rev[reg].."'")
+ end
+
+ -- [reg] or [reg+-disp]
+ t.disp = toint(tailr) or (tailr == "" and 0)
+ if t.disp then break end
+
+ -- [reg+xreg...]
+ local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$")
+ xreg, t.xreg, tp = rtexpr(xreg)
+ if not t.xreg then
+ -- [reg+-expr]
+ t.disp = dispexpr(tailr)
+ break
+ end
+ if not map_reg_valid_index[xreg] then
+ werror("bad index register `"..map_reg_rev[xreg].."'")
+ end
+
+ if t.xreg == -1 then
+ t.vxreg, tailx = match(tailx, "^(%b())(.*)$")
+ if not t.vxreg then werror("bad variable register expression") end
+ end
+
+ -- [reg+xreg*xsc...]
+ local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$")
+ if xsc then
+ t.xsc = map_xsc[xsc]
+ tailx = tailsc
+ end
+
+ -- [...] or [...+-disp] or [...+-expr]
+ t.disp = dispexpr(tailx)
+ else
+ -- imm or opsize*imm
+ local imm = toint(expr)
+ if not imm and sub(expr, 1, 1) == "*" and t.opsize then
+ imm = toint(sub(expr, 2))
+ if imm then
+ imm = imm * map_opsizenum[t.opsize]
+ t.opsize = nil
+ end
+ end
+ if imm then
+ if t.opsize then werror("bad operand size override") end
+ local m = "i"
+ if imm == 1 then m = m.."1" end
+ if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end
+ if imm >= -128 and imm <= 127 then m = m.."S" end
+ t.imm = imm
+ t.mode = m
+ break
+ end
+
+ local tp
+ local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$")
+ reg, t.reg, tp = rtexpr(reg)
+ if t.reg then
+ if t.reg == -1 then
+ t.vreg, tailr = match(tailr, "^(%b())(.*)$")
+ if not t.vreg then werror("bad variable register expression") end
+ end
+ -- reg
+ if tailr == "" then
+ if t.opsize then werror("bad operand size override") end
+ t.opsize = map_reg_opsize[reg]
+ if t.opsize == "f" then
+ t.mode = t.reg == 0 and "fF" or "f"
+ else
+ if reg == "@w4" or (x64 and reg == "@d4") then
+ wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'"))
+ end
+ t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm")
+ end
+ t.needrex = map_reg_needrex[reg]
+ break
+ end
+
+ -- type[idx], type[idx].field, type->field -> [reg+offset_expr]
+ if not tp then werror("bad operand `"..param.."'") end
+ t.mode = "xm"
+ t.disp = format(tp.ctypefmt, tailr)
+ else
+ t.mode, t.imm = immexpr(expr)
+ if sub(t.mode, -1) == "J" then
+ if t.opsize and t.opsize ~= addrsize then
+ werror("bad operand size override")
+ end
+ t.opsize = addrsize
+ end
+ end
+ end
+ until true
+ return t
+end
+
+------------------------------------------------------------------------------
+-- x86 Template String Description
+-- ===============================
+--
+-- Each template string is a list of [match:]pattern pairs,
+-- separated by "|". The first match wins. No match means a
+-- bad or unsupported combination of operand modes or sizes.
+--
+-- The match part and the ":" is omitted if the operation has
+-- no operands. Otherwise the first N characters are matched
+-- against the mode strings of each of the N operands.
+--
+-- The mode string for each operand type is (see parseoperand()):
+-- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl
+-- FP register: "f", +"F" for st0
+-- Index operand: "xm", +"O" for [disp] (pure offset)
+-- Immediate: "i", +"S" for signed 8 bit, +"1" for 1,
+-- +"I" for arg, +"P" for pointer
+-- Any: +"J" for valid jump targets
+--
+-- So a match character "m" (mixed) matches both an integer register
+-- and an index operand (to be encoded with the ModRM/SIB scheme).
+-- But "r" matches only a register and "x" only an index operand
+-- (e.g. for FP memory access operations).
+--
+-- The operand size match string starts right after the mode match
+-- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty.
+-- The effective data size of the operation is matched against this list.
+--
+-- If only the regular "b", "w", "d", "q", "t" operand sizes are
+-- present, then all operands must be the same size. Unspecified sizes
+-- are ignored, but at least one operand must have a size or the pattern
+-- won't match (use the "byte", "word", "dword", "qword", "tword"
+-- operand size overrides. E.g.: mov dword [eax], 1).
+--
+-- If the list has a "1" or "2" prefix, the operand size is taken
+-- from the respective operand and any other operand sizes are ignored.
+-- If the list contains only ".", all operand sizes are ignored.
+-- If the list has a "/" prefix, the concatenated (mixed) operand sizes
+-- are compared to the match.
+--
+-- E.g. "rrdw" matches for either two dword registers or two word
+-- registers. "Fx2dq" matches an st0 operand plus an index operand
+-- pointing to a dword (float) or qword (double).
+--
+-- Every character after the ":" is part of the pattern string:
+-- Hex chars are accumulated to form the opcode (left to right).
+-- "n" disables the standard opcode mods
+-- (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q")
+-- "X" Force REX.W.
+-- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode.
+-- "m"/"M" generates ModRM/SIB from the 1st/2nd operand.
+-- The spare 3 bits are either filled with the last hex digit or
+-- the result from a previous "r"/"R". The opcode is restored.
+-- "u" Use VEX encoding, vvvv unused.
+-- "v"/"V" Use VEX encoding, vvvv from 1st/2nd operand (the operand is
+-- removed from the list used by future characters).
+-- "L" Force VEX.L
+--
+-- All of the following characters force a flush of the opcode:
+-- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand.
+-- "s" stores a 4 bit immediate from the last register operand,
+-- followed by 4 zero bits.
+-- "S" stores a signed 8 bit immediate from the last operand.
+-- "U" stores an unsigned 8 bit immediate from the last operand.
+-- "W" stores an unsigned 16 bit immediate from the last operand.
+-- "i" stores an operand sized immediate from the last operand.
+-- "I" dito, but generates an action code to optionally modify
+-- the opcode (+2) for a signed 8 bit immediate.
+-- "J" generates one of the REL action codes from the last operand.
+--
+------------------------------------------------------------------------------
+
+-- Template strings for x86 instructions. Ordered by first opcode byte.
+-- Unimplemented opcodes (deliberate omissions) are marked with *.
+local map_op = {
+ -- 00-05: add...
+ -- 06: *push es
+ -- 07: *pop es
+ -- 08-0D: or...
+ -- 0E: *push cs
+ -- 0F: two byte opcode prefix
+ -- 10-15: adc...
+ -- 16: *push ss
+ -- 17: *pop ss
+ -- 18-1D: sbb...
+ -- 1E: *push ds
+ -- 1F: *pop ds
+ -- 20-25: and...
+ es_0 = "26",
+ -- 27: *daa
+ -- 28-2D: sub...
+ cs_0 = "2E",
+ -- 2F: *das
+ -- 30-35: xor...
+ ss_0 = "36",
+ -- 37: *aaa
+ -- 38-3D: cmp...
+ ds_0 = "3E",
+ -- 3F: *aas
+ inc_1 = x64 and "m:FF0m" or "rdw:40r|m:FF0m",
+ dec_1 = x64 and "m:FF1m" or "rdw:48r|m:FF1m",
+ push_1 = (x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or
+ "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i",
+ pop_1 = x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m",
+ -- 60: *pusha, *pushad, *pushaw
+ -- 61: *popa, *popad, *popaw
+ -- 62: *bound rdw,x
+ -- 63: x86: *arpl mw,rw
+ movsxd_2 = x64 and "rm/qd:63rM",
+ fs_0 = "64",
+ gs_0 = "65",
+ o16_0 = "66",
+ a16_0 = not x64 and "67" or nil,
+ a32_0 = x64 and "67",
+ -- 68: push idw
+ -- 69: imul rdw,mdw,idw
+ -- 6A: push ib
+ -- 6B: imul rdw,mdw,S
+ -- 6C: *insb
+ -- 6D: *insd, *insw
+ -- 6E: *outsb
+ -- 6F: *outsd, *outsw
+ -- 70-7F: jcc lb
+ -- 80: add... mb,i
+ -- 81: add... mdw,i
+ -- 82: *undefined
+ -- 83: add... mdw,S
+ test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi",
+ -- 86: xchg rb,mb
+ -- 87: xchg rdw,mdw
+ -- 88: mov mb,r
+ -- 89: mov mdw,r
+ -- 8A: mov r,mb
+ -- 8B: mov r,mdw
+ -- 8C: *mov mdw,seg
+ lea_2 = "rx1dq:8DrM",
+ -- 8E: *mov seg,mdw
+ -- 8F: pop mdw
+ nop_0 = "90",
+ xchg_2 = "Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm",
+ cbw_0 = "6698",
+ cwde_0 = "98",
+ cdqe_0 = "4898",
+ cwd_0 = "6699",
+ cdq_0 = "99",
+ cqo_0 = "4899",
+ -- 9A: *call iw:idw
+ wait_0 = "9B",
+ fwait_0 = "9B",
+ pushf_0 = "9C",
+ pushfd_0 = not x64 and "9C",
+ pushfq_0 = x64 and "9C",
+ popf_0 = "9D",
+ popfd_0 = not x64 and "9D",
+ popfq_0 = x64 and "9D",
+ sahf_0 = "9E",
+ lahf_0 = "9F",
+ mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi",
+ movsb_0 = "A4",
+ movsw_0 = "66A5",
+ movsd_0 = "A5",
+ cmpsb_0 = "A6",
+ cmpsw_0 = "66A7",
+ cmpsd_0 = "A7",
+ -- A8: test Rb,i
+ -- A9: test Rdw,i
+ stosb_0 = "AA",
+ stosw_0 = "66AB",
+ stosd_0 = "AB",
+ lodsb_0 = "AC",
+ lodsw_0 = "66AD",
+ lodsd_0 = "AD",
+ scasb_0 = "AE",
+ scasw_0 = "66AF",
+ scasd_0 = "AF",
+ -- B0-B7: mov rb,i
+ -- B8-BF: mov rdw,i
+ -- C0: rol... mb,i
+ -- C1: rol... mdw,i
+ ret_1 = "i.:nC2W",
+ ret_0 = "C3",
+ -- C4: *les rdw,mq
+ -- C5: *lds rdw,mq
+ -- C6: mov mb,i
+ -- C7: mov mdw,i
+ -- C8: *enter iw,ib
+ leave_0 = "C9",
+ -- CA: *retf iw
+ -- CB: *retf
+ int3_0 = "CC",
+ int_1 = "i.:nCDU",
+ into_0 = "CE",
+ -- CF: *iret
+ -- D0: rol... mb,1
+ -- D1: rol... mdw,1
+ -- D2: rol... mb,cl
+ -- D3: rol... mb,cl
+ -- D4: *aam ib
+ -- D5: *aad ib
+ -- D6: *salc
+ -- D7: *xlat
+ -- D8-DF: floating point ops
+ -- E0: *loopne
+ -- E1: *loope
+ -- E2: *loop
+ -- E3: *jcxz, *jecxz
+ -- E4: *in Rb,ib
+ -- E5: *in Rdw,ib
+ -- E6: *out ib,Rb
+ -- E7: *out ib,Rdw
+ call_1 = x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J",
+ jmp_1 = x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB
+ -- EA: *jmp iw:idw
+ -- EB: jmp ib
+ -- EC: *in Rb,dx
+ -- ED: *in Rdw,dx
+ -- EE: *out dx,Rb
+ -- EF: *out dx,Rdw
+ lock_0 = "F0",
+ int1_0 = "F1",
+ repne_0 = "F2",
+ repnz_0 = "F2",
+ rep_0 = "F3",
+ repe_0 = "F3",
+ repz_0 = "F3",
+ -- F4: *hlt
+ cmc_0 = "F5",
+ -- F6: test... mb,i; div... mb
+ -- F7: test... mdw,i; div... mdw
+ clc_0 = "F8",
+ stc_0 = "F9",
+ -- FA: *cli
+ cld_0 = "FC",
+ std_0 = "FD",
+ -- FE: inc... mb
+ -- FF: inc... mdw
+
+ -- misc ops
+ not_1 = "m:F72m",
+ neg_1 = "m:F73m",
+ mul_1 = "m:F74m",
+ imul_1 = "m:F75m",
+ div_1 = "m:F76m",
+ idiv_1 = "m:F77m",
+
+ imul_2 = "rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi",
+ imul_3 = "rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi",
+
+ movzx_2 = "rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:",
+ movsx_2 = "rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:",
+
+ bswap_1 = "rqd:0FC8r",
+ bsf_2 = "rmqdw:0FBCrM",
+ bsr_2 = "rmqdw:0FBDrM",
+ bt_2 = "mrqdw:0FA3Rm|miqdw:0FBA4mU",
+ btc_2 = "mrqdw:0FBBRm|miqdw:0FBA7mU",
+ btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU",
+ bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU",
+
+ shld_3 = "mriqdw:0FA4RmU|mrC/qq:0FA5Rm|mrC/dd:|mrC/ww:",
+ shrd_3 = "mriqdw:0FACRmU|mrC/qq:0FADRm|mrC/dd:|mrC/ww:",
+
+ rdtsc_0 = "0F31", -- P1+
+ rdpmc_0 = "0F33", -- P6+
+ cpuid_0 = "0FA2", -- P1+
+
+ -- floating point ops
+ fst_1 = "ff:DDD0r|xd:D92m|xq:nDD2m",
+ fstp_1 = "ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m",
+ fld_1 = "ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m",
+
+ fpop_0 = "DDD8", -- Alias for fstp st0.
+
+ fist_1 = "xw:nDF2m|xd:DB2m",
+ fistp_1 = "xw:nDF3m|xd:DB3m|xq:nDF7m",
+ fild_1 = "xw:nDF0m|xd:DB0m|xq:nDF5m",
+
+ fxch_0 = "D9C9",
+ fxch_1 = "ff:D9C8r",
+ fxch_2 = "fFf:D9C8r|Fff:D9C8R",
+
+ fucom_1 = "ff:DDE0r",
+ fucom_2 = "Fff:DDE0R",
+ fucomp_1 = "ff:DDE8r",
+ fucomp_2 = "Fff:DDE8R",
+ fucomi_1 = "ff:DBE8r", -- P6+
+ fucomi_2 = "Fff:DBE8R", -- P6+
+ fucomip_1 = "ff:DFE8r", -- P6+
+ fucomip_2 = "Fff:DFE8R", -- P6+
+ fcomi_1 = "ff:DBF0r", -- P6+
+ fcomi_2 = "Fff:DBF0R", -- P6+
+ fcomip_1 = "ff:DFF0r", -- P6+
+ fcomip_2 = "Fff:DFF0R", -- P6+
+ fucompp_0 = "DAE9",
+ fcompp_0 = "DED9",
+
+ fldenv_1 = "x.:D94m",
+ fnstenv_1 = "x.:D96m",
+ fstenv_1 = "x.:9BD96m",
+ fldcw_1 = "xw:nD95m",
+ fstcw_1 = "xw:n9BD97m",
+ fnstcw_1 = "xw:nD97m",
+ fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m",
+ fnstsw_1 = "Rw:nDFE0|xw:nDD7m",
+ fclex_0 = "9BDBE2",
+ fnclex_0 = "DBE2",
+
+ fnop_0 = "D9D0",
+ -- D9D1-D9DF: unassigned
+
+ fchs_0 = "D9E0",
+ fabs_0 = "D9E1",
+ -- D9E2: unassigned
+ -- D9E3: unassigned
+ ftst_0 = "D9E4",
+ fxam_0 = "D9E5",
+ -- D9E6: unassigned
+ -- D9E7: unassigned
+ fld1_0 = "D9E8",
+ fldl2t_0 = "D9E9",
+ fldl2e_0 = "D9EA",
+ fldpi_0 = "D9EB",
+ fldlg2_0 = "D9EC",
+ fldln2_0 = "D9ED",
+ fldz_0 = "D9EE",
+ -- D9EF: unassigned
+
+ f2xm1_0 = "D9F0",
+ fyl2x_0 = "D9F1",
+ fptan_0 = "D9F2",
+ fpatan_0 = "D9F3",
+ fxtract_0 = "D9F4",
+ fprem1_0 = "D9F5",
+ fdecstp_0 = "D9F6",
+ fincstp_0 = "D9F7",
+ fprem_0 = "D9F8",
+ fyl2xp1_0 = "D9F9",
+ fsqrt_0 = "D9FA",
+ fsincos_0 = "D9FB",
+ frndint_0 = "D9FC",
+ fscale_0 = "D9FD",
+ fsin_0 = "D9FE",
+ fcos_0 = "D9FF",
+
+ -- SSE, SSE2
+ andnpd_2 = "rmo:660F55rM",
+ andnps_2 = "rmo:0F55rM",
+ andpd_2 = "rmo:660F54rM",
+ andps_2 = "rmo:0F54rM",
+ clflush_1 = "x.:0FAE7m",
+ cmppd_3 = "rmio:660FC2rMU",
+ cmpps_3 = "rmio:0FC2rMU",
+ cmpsd_3 = "rrio:F20FC2rMU|rxi/oq:",
+ cmpss_3 = "rrio:F30FC2rMU|rxi/od:",
+ comisd_2 = "rro:660F2FrM|rx/oq:",
+ comiss_2 = "rro:0F2FrM|rx/od:",
+ cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:",
+ cvtdq2ps_2 = "rmo:0F5BrM",
+ cvtpd2dq_2 = "rmo:F20FE6rM",
+ cvtpd2ps_2 = "rmo:660F5ArM",
+ cvtpi2pd_2 = "rx/oq:660F2ArM",
+ cvtpi2ps_2 = "rx/oq:0F2ArM",
+ cvtps2dq_2 = "rmo:660F5BrM",
+ cvtps2pd_2 = "rro:0F5ArM|rx/oq:",
+ cvtsd2si_2 = "rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:",
+ cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:",
+ cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM",
+ cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM",
+ cvtss2sd_2 = "rro:F30F5ArM|rx/od:",
+ cvtss2si_2 = "rr/do:F30F2DrM|rr/qo:|rxd:|rx/qd:",
+ cvttpd2dq_2 = "rmo:660FE6rM",
+ cvttps2dq_2 = "rmo:F30F5BrM",
+ cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:",
+ cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:",
+ fxsave_1 = "x.:0FAE0m",
+ fxrstor_1 = "x.:0FAE1m",
+ ldmxcsr_1 = "xd:0FAE2m",
+ lfence_0 = "0FAEE8",
+ maskmovdqu_2 = "rro:660FF7rM",
+ mfence_0 = "0FAEF0",
+ movapd_2 = "rmo:660F28rM|mro:660F29Rm",
+ movaps_2 = "rmo:0F28rM|mro:0F29Rm",
+ movd_2 = "rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:",
+ movdqa_2 = "rmo:660F6FrM|mro:660F7FRm",
+ movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm",
+ movhlps_2 = "rro:0F12rM",
+ movhpd_2 = "rx/oq:660F16rM|xr/qo:n660F17Rm",
+ movhps_2 = "rx/oq:0F16rM|xr/qo:n0F17Rm",
+ movlhps_2 = "rro:0F16rM",
+ movlpd_2 = "rx/oq:660F12rM|xr/qo:n660F13Rm",
+ movlps_2 = "rx/oq:0F12rM|xr/qo:n0F13Rm",
+ movmskpd_2 = "rr/do:660F50rM",
+ movmskps_2 = "rr/do:0F50rM",
+ movntdq_2 = "xro:660FE7Rm",
+ movnti_2 = "xrqd:0FC3Rm",
+ movntpd_2 = "xro:660F2BRm",
+ movntps_2 = "xro:0F2BRm",
+ movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm",
+ movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm",
+ movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm",
+ movupd_2 = "rmo:660F10rM|mro:660F11Rm",
+ movups_2 = "rmo:0F10rM|mro:0F11Rm",
+ orpd_2 = "rmo:660F56rM",
+ orps_2 = "rmo:0F56rM",
+ pause_0 = "F390",
+ pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nRmU", -- Mem op: SSE4.1 only.
+ pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:",
+ pmovmskb_2 = "rr/do:660FD7rM",
+ prefetchnta_1 = "xb:n0F180m",
+ prefetcht0_1 = "xb:n0F181m",
+ prefetcht1_1 = "xb:n0F182m",
+ prefetcht2_1 = "xb:n0F183m",
+ pshufd_3 = "rmio:660F70rMU",
+ pshufhw_3 = "rmio:F30F70rMU",
+ pshuflw_3 = "rmio:F20F70rMU",
+ pslld_2 = "rmo:660FF2rM|rio:660F726mU",
+ pslldq_2 = "rio:660F737mU",
+ psllq_2 = "rmo:660FF3rM|rio:660F736mU",
+ psllw_2 = "rmo:660FF1rM|rio:660F716mU",
+ psrad_2 = "rmo:660FE2rM|rio:660F724mU",
+ psraw_2 = "rmo:660FE1rM|rio:660F714mU",
+ psrld_2 = "rmo:660FD2rM|rio:660F722mU",
+ psrldq_2 = "rio:660F733mU",
+ psrlq_2 = "rmo:660FD3rM|rio:660F732mU",
+ psrlw_2 = "rmo:660FD1rM|rio:660F712mU",
+ rcpps_2 = "rmo:0F53rM",
+ rcpss_2 = "rro:F30F53rM|rx/od:",
+ rsqrtps_2 = "rmo:0F52rM",
+ rsqrtss_2 = "rmo:F30F52rM",
+ sfence_0 = "0FAEF8",
+ shufpd_3 = "rmio:660FC6rMU",
+ shufps_3 = "rmio:0FC6rMU",
+ stmxcsr_1 = "xd:0FAE3m",
+ ucomisd_2 = "rro:660F2ErM|rx/oq:",
+ ucomiss_2 = "rro:0F2ErM|rx/od:",
+ unpckhpd_2 = "rmo:660F15rM",
+ unpckhps_2 = "rmo:0F15rM",
+ unpcklpd_2 = "rmo:660F14rM",
+ unpcklps_2 = "rmo:0F14rM",
+ xorpd_2 = "rmo:660F57rM",
+ xorps_2 = "rmo:0F57rM",
+
+ -- SSE3 ops
+ fisttp_1 = "xw:nDF1m|xd:DB1m|xq:nDD1m",
+ addsubpd_2 = "rmo:660FD0rM",
+ addsubps_2 = "rmo:F20FD0rM",
+ haddpd_2 = "rmo:660F7CrM",
+ haddps_2 = "rmo:F20F7CrM",
+ hsubpd_2 = "rmo:660F7DrM",
+ hsubps_2 = "rmo:F20F7DrM",
+ lddqu_2 = "rxo:F20FF0rM",
+ movddup_2 = "rmo:F20F12rM",
+ movshdup_2 = "rmo:F30F16rM",
+ movsldup_2 = "rmo:F30F12rM",
+
+ -- SSSE3 ops
+ pabsb_2 = "rmo:660F381CrM",
+ pabsd_2 = "rmo:660F381ErM",
+ pabsw_2 = "rmo:660F381DrM",
+ palignr_3 = "rmio:660F3A0FrMU",
+ phaddd_2 = "rmo:660F3802rM",
+ phaddsw_2 = "rmo:660F3803rM",
+ phaddw_2 = "rmo:660F3801rM",
+ phsubd_2 = "rmo:660F3806rM",
+ phsubsw_2 = "rmo:660F3807rM",
+ phsubw_2 = "rmo:660F3805rM",
+ pmaddubsw_2 = "rmo:660F3804rM",
+ pmulhrsw_2 = "rmo:660F380BrM",
+ pshufb_2 = "rmo:660F3800rM",
+ psignb_2 = "rmo:660F3808rM",
+ psignd_2 = "rmo:660F380ArM",
+ psignw_2 = "rmo:660F3809rM",
+
+ -- SSE4.1 ops
+ blendpd_3 = "rmio:660F3A0DrMU",
+ blendps_3 = "rmio:660F3A0CrMU",
+ blendvpd_3 = "rmRo:660F3815rM",
+ blendvps_3 = "rmRo:660F3814rM",
+ dppd_3 = "rmio:660F3A41rMU",
+ dpps_3 = "rmio:660F3A40rMU",
+ extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU",
+ insertps_3 = "rrio:660F3A41rMU|rxi/od:",
+ movntdqa_2 = "rxo:660F382ArM",
+ mpsadbw_3 = "rmio:660F3A42rMU",
+ packusdw_2 = "rmo:660F382BrM",
+ pblendvb_3 = "rmRo:660F3810rM",
+ pblendw_3 = "rmio:660F3A0ErMU",
+ pcmpeqq_2 = "rmo:660F3829rM",
+ pextrb_3 = "rri/do:660F3A14nRmU|rri/qo:|xri/bo:",
+ pextrd_3 = "mri/do:660F3A16RmU",
+ pextrq_3 = "mri/qo:660F3A16RmU",
+ -- pextrw is SSE2, mem operand is SSE4.1 only
+ phminposuw_2 = "rmo:660F3841rM",
+ pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:",
+ pinsrd_3 = "rmi/od:660F3A22rMU",
+ pinsrq_3 = "rmi/oq:660F3A22rXMU",
+ pmaxsb_2 = "rmo:660F383CrM",
+ pmaxsd_2 = "rmo:660F383DrM",
+ pmaxud_2 = "rmo:660F383FrM",
+ pmaxuw_2 = "rmo:660F383ErM",
+ pminsb_2 = "rmo:660F3838rM",
+ pminsd_2 = "rmo:660F3839rM",
+ pminud_2 = "rmo:660F383BrM",
+ pminuw_2 = "rmo:660F383ArM",
+ pmovsxbd_2 = "rro:660F3821rM|rx/od:",
+ pmovsxbq_2 = "rro:660F3822rM|rx/ow:",
+ pmovsxbw_2 = "rro:660F3820rM|rx/oq:",
+ pmovsxdq_2 = "rro:660F3825rM|rx/oq:",
+ pmovsxwd_2 = "rro:660F3823rM|rx/oq:",
+ pmovsxwq_2 = "rro:660F3824rM|rx/od:",
+ pmovzxbd_2 = "rro:660F3831rM|rx/od:",
+ pmovzxbq_2 = "rro:660F3832rM|rx/ow:",
+ pmovzxbw_2 = "rro:660F3830rM|rx/oq:",
+ pmovzxdq_2 = "rro:660F3835rM|rx/oq:",
+ pmovzxwd_2 = "rro:660F3833rM|rx/oq:",
+ pmovzxwq_2 = "rro:660F3834rM|rx/od:",
+ pmuldq_2 = "rmo:660F3828rM",
+ pmulld_2 = "rmo:660F3840rM",
+ ptest_2 = "rmo:660F3817rM",
+ roundpd_3 = "rmio:660F3A09rMU",
+ roundps_3 = "rmio:660F3A08rMU",
+ roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:",
+ roundss_3 = "rrio:660F3A0ArMU|rxi/od:",
+
+ -- SSE4.2 ops
+ crc32_2 = "rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:",
+ pcmpestri_3 = "rmio:660F3A61rMU",
+ pcmpestrm_3 = "rmio:660F3A60rMU",
+ pcmpgtq_2 = "rmo:660F3837rM",
+ pcmpistri_3 = "rmio:660F3A63rMU",
+ pcmpistrm_3 = "rmio:660F3A62rMU",
+ popcnt_2 = "rmqdw:F30FB8rM",
+
+ -- SSE4a
+ extrq_2 = "rro:660F79rM",
+ extrq_3 = "riio:660F780mUU",
+ insertq_2 = "rro:F20F79rM",
+ insertq_4 = "rriio:F20F78rMUU",
+ lzcnt_2 = "rmqdw:F30FBDrM",
+ movntsd_2 = "xr/qo:nF20F2BRm",
+ movntss_2 = "xr/do:F30F2BRm",
+ -- popcnt is also in SSE4.2
+
+ -- AES-NI
+ aesdec_2 = "rmo:660F38DErM",
+ aesdeclast_2 = "rmo:660F38DFrM",
+ aesenc_2 = "rmo:660F38DCrM",
+ aesenclast_2 = "rmo:660F38DDrM",
+ aesimc_2 = "rmo:660F38DBrM",
+ aeskeygenassist_3 = "rmio:660F3ADFrMU",
+ pclmulqdq_3 = "rmio:660F3A44rMU",
+
+ -- AVX FP ops
+ vaddsubpd_3 = "rrmoy:660FVD0rM",
+ vaddsubps_3 = "rrmoy:F20FVD0rM",
+ vandpd_3 = "rrmoy:660FV54rM",
+ vandps_3 = "rrmoy:0FV54rM",
+ vandnpd_3 = "rrmoy:660FV55rM",
+ vandnps_3 = "rrmoy:0FV55rM",
+ vblendpd_4 = "rrmioy:660F3AV0DrMU",
+ vblendps_4 = "rrmioy:660F3AV0CrMU",
+ vblendvpd_4 = "rrmroy:660F3AV4BrMs",
+ vblendvps_4 = "rrmroy:660F3AV4ArMs",
+ vbroadcastf128_2 = "rx/yo:660F38u1ArM",
+ vcmppd_4 = "rrmioy:660FVC2rMU",
+ vcmpps_4 = "rrmioy:0FVC2rMU",
+ vcmpsd_4 = "rrrio:F20FVC2rMU|rrxi/ooq:",
+ vcmpss_4 = "rrrio:F30FVC2rMU|rrxi/ood:",
+ vcomisd_2 = "rro:660Fu2FrM|rx/oq:",
+ vcomiss_2 = "rro:0Fu2FrM|rx/od:",
+ vcvtdq2pd_2 = "rro:F30FuE6rM|rx/oq:|rm/yo:",
+ vcvtdq2ps_2 = "rmoy:0Fu5BrM",
+ vcvtpd2dq_2 = "rmoy:F20FuE6rM",
+ vcvtpd2ps_2 = "rmoy:660Fu5ArM",
+ vcvtps2dq_2 = "rmoy:660Fu5BrM",
+ vcvtps2pd_2 = "rro:0Fu5ArM|rx/oq:|rm/yo:",
+ vcvtsd2si_2 = "rr/do:F20Fu2DrM|rx/dq:|rr/qo:|rxq:",
+ vcvtsd2ss_3 = "rrro:F20FV5ArM|rrx/ooq:",
+ vcvtsi2sd_3 = "rrm/ood:F20FV2ArM|rrm/ooq:F20FVX2ArM",
+ vcvtsi2ss_3 = "rrm/ood:F30FV2ArM|rrm/ooq:F30FVX2ArM",
+ vcvtss2sd_3 = "rrro:F30FV5ArM|rrx/ood:",
+ vcvtss2si_2 = "rr/do:F30Fu2DrM|rxd:|rr/qo:|rx/qd:",
+ vcvttpd2dq_2 = "rmo:660FuE6rM|rm/oy:660FuLE6rM",
+ vcvttps2dq_2 = "rmoy:F30Fu5BrM",
+ vcvttsd2si_2 = "rr/do:F20Fu2CrM|rx/dq:|rr/qo:|rxq:",
+ vcvttss2si_2 = "rr/do:F30Fu2CrM|rxd:|rr/qo:|rx/qd:",
+ vdppd_4 = "rrmio:660F3AV41rMU",
+ vdpps_4 = "rrmioy:660F3AV40rMU",
+ vextractf128_3 = "mri/oy:660F3AuL19RmU",
+ vextractps_3 = "mri/do:660F3Au17RmU",
+ vhaddpd_3 = "rrmoy:660FV7CrM",
+ vhaddps_3 = "rrmoy:F20FV7CrM",
+ vhsubpd_3 = "rrmoy:660FV7DrM",
+ vhsubps_3 = "rrmoy:F20FV7DrM",
+ vinsertf128_4 = "rrmi/yyo:660F3AV18rMU",
+ vinsertps_4 = "rrrio:660F3AV21rMU|rrxi/ood:",
+ vldmxcsr_1 = "xd:0FuAE2m",
+ vmaskmovps_3 = "rrxoy:660F38V2CrM|xrroy:660F38V2ERm",
+ vmaskmovpd_3 = "rrxoy:660F38V2DrM|xrroy:660F38V2FRm",
+ vmovapd_2 = "rmoy:660Fu28rM|mroy:660Fu29Rm",
+ vmovaps_2 = "rmoy:0Fu28rM|mroy:0Fu29Rm",
+ vmovd_2 = "rm/od:660Fu6ErM|rm/oq:660FuX6ErM|mr/do:660Fu7ERm|mr/qo:",
+ vmovq_2 = "rro:F30Fu7ErM|rx/oq:|xr/qo:660FuD6Rm",
+ vmovddup_2 = "rmy:F20Fu12rM|rro:|rx/oq:",
+ vmovhlps_3 = "rrro:0FV12rM",
+ vmovhpd_2 = "xr/qo:660Fu17Rm",
+ vmovhpd_3 = "rrx/ooq:660FV16rM",
+ vmovhps_2 = "xr/qo:0Fu17Rm",
+ vmovhps_3 = "rrx/ooq:0FV16rM",
+ vmovlhps_3 = "rrro:0FV16rM",
+ vmovlpd_2 = "xr/qo:660Fu13Rm",
+ vmovlpd_3 = "rrx/ooq:660FV12rM",
+ vmovlps_2 = "xr/qo:0Fu13Rm",
+ vmovlps_3 = "rrx/ooq:0FV12rM",
+ vmovmskpd_2 = "rr/do:660Fu50rM|rr/dy:660FuL50rM",
+ vmovmskps_2 = "rr/do:0Fu50rM|rr/dy:0FuL50rM",
+ vmovntpd_2 = "xroy:660Fu2BRm",
+ vmovntps_2 = "xroy:0Fu2BRm",
+ vmovsd_2 = "rx/oq:F20Fu10rM|xr/qo:F20Fu11Rm",
+ vmovsd_3 = "rrro:F20FV10rM",
+ vmovshdup_2 = "rmoy:F30Fu16rM",
+ vmovsldup_2 = "rmoy:F30Fu12rM",
+ vmovss_2 = "rx/od:F30Fu10rM|xr/do:F30Fu11Rm",
+ vmovss_3 = "rrro:F30FV10rM",
+ vmovupd_2 = "rmoy:660Fu10rM|mroy:660Fu11Rm",
+ vmovups_2 = "rmoy:0Fu10rM|mroy:0Fu11Rm",
+ vorpd_3 = "rrmoy:660FV56rM",
+ vorps_3 = "rrmoy:0FV56rM",
+ vpermilpd_3 = "rrmoy:660F38V0DrM|rmioy:660F3Au05rMU",
+ vpermilps_3 = "rrmoy:660F38V0CrM|rmioy:660F3Au04rMU",
+ vperm2f128_4 = "rrmiy:660F3AV06rMU",
+ vptestpd_2 = "rmoy:660F38u0FrM",
+ vptestps_2 = "rmoy:660F38u0ErM",
+ vrcpps_2 = "rmoy:0Fu53rM",
+ vrcpss_3 = "rrro:F30FV53rM|rrx/ood:",
+ vrsqrtps_2 = "rmoy:0Fu52rM",
+ vrsqrtss_3 = "rrro:F30FV52rM|rrx/ood:",
+ vroundpd_3 = "rmioy:660F3AV09rMU",
+ vroundps_3 = "rmioy:660F3AV08rMU",
+ vroundsd_4 = "rrrio:660F3AV0BrMU|rrxi/ooq:",
+ vroundss_4 = "rrrio:660F3AV0ArMU|rrxi/ood:",
+ vshufpd_4 = "rrmioy:660FVC6rMU",
+ vshufps_4 = "rrmioy:0FVC6rMU",
+ vsqrtps_2 = "rmoy:0Fu51rM",
+ vsqrtss_2 = "rro:F30Fu51rM|rx/od:",
+ vsqrtpd_2 = "rmoy:660Fu51rM",
+ vsqrtsd_2 = "rro:F20Fu51rM|rx/oq:",
+ vstmxcsr_1 = "xd:0FuAE3m",
+ vucomisd_2 = "rro:660Fu2ErM|rx/oq:",
+ vucomiss_2 = "rro:0Fu2ErM|rx/od:",
+ vunpckhpd_3 = "rrmoy:660FV15rM",
+ vunpckhps_3 = "rrmoy:0FV15rM",
+ vunpcklpd_3 = "rrmoy:660FV14rM",
+ vunpcklps_3 = "rrmoy:0FV14rM",
+ vxorpd_3 = "rrmoy:660FV57rM",
+ vxorps_3 = "rrmoy:0FV57rM",
+ vzeroall_0 = "0FuL77",
+ vzeroupper_0 = "0Fu77",
+
+ -- AVX2 FP ops
+ vbroadcastss_2 = "rx/od:660F38u18rM|rx/yd:|rro:|rr/yo:",
+ vbroadcastsd_2 = "rx/yq:660F38u19rM|rr/yo:",
+ -- *vgather* (!vsib)
+ vpermpd_3 = "rmiy:660F3AuX01rMU",
+ vpermps_3 = "rrmy:660F38V16rM",
+
+ -- AVX, AVX2 integer ops
+ -- In general, xmm requires AVX, ymm requires AVX2.
+ vaesdec_3 = "rrmo:660F38VDErM",
+ vaesdeclast_3 = "rrmo:660F38VDFrM",
+ vaesenc_3 = "rrmo:660F38VDCrM",
+ vaesenclast_3 = "rrmo:660F38VDDrM",
+ vaesimc_2 = "rmo:660F38uDBrM",
+ vaeskeygenassist_3 = "rmio:660F3AuDFrMU",
+ vlddqu_2 = "rxoy:F20FuF0rM",
+ vmaskmovdqu_2 = "rro:660FuF7rM",
+ vmovdqa_2 = "rmoy:660Fu6FrM|mroy:660Fu7FRm",
+ vmovdqu_2 = "rmoy:F30Fu6FrM|mroy:F30Fu7FRm",
+ vmovntdq_2 = "xroy:660FuE7Rm",
+ vmovntdqa_2 = "rxoy:660F38u2ArM",
+ vmpsadbw_4 = "rrmioy:660F3AV42rMU",
+ vpabsb_2 = "rmoy:660F38u1CrM",
+ vpabsd_2 = "rmoy:660F38u1ErM",
+ vpabsw_2 = "rmoy:660F38u1DrM",
+ vpackusdw_3 = "rrmoy:660F38V2BrM",
+ vpalignr_4 = "rrmioy:660F3AV0FrMU",
+ vpblendvb_4 = "rrmroy:660F3AV4CrMs",
+ vpblendw_4 = "rrmioy:660F3AV0ErMU",
+ vpclmulqdq_4 = "rrmio:660F3AV44rMU",
+ vpcmpeqq_3 = "rrmoy:660F38V29rM",
+ vpcmpestri_3 = "rmio:660F3Au61rMU",
+ vpcmpestrm_3 = "rmio:660F3Au60rMU",
+ vpcmpgtq_3 = "rrmoy:660F38V37rM",
+ vpcmpistri_3 = "rmio:660F3Au63rMU",
+ vpcmpistrm_3 = "rmio:660F3Au62rMU",
+ vpextrb_3 = "rri/do:660F3Au14nRmU|rri/qo:|xri/bo:",
+ vpextrw_3 = "rri/do:660FuC5rMU|xri/wo:660F3Au15nRmU",
+ vpextrd_3 = "mri/do:660F3Au16RmU",
+ vpextrq_3 = "mri/qo:660F3Au16RmU",
+ vphaddw_3 = "rrmoy:660F38V01rM",
+ vphaddd_3 = "rrmoy:660F38V02rM",
+ vphaddsw_3 = "rrmoy:660F38V03rM",
+ vphminposuw_2 = "rmo:660F38u41rM",
+ vphsubw_3 = "rrmoy:660F38V05rM",
+ vphsubd_3 = "rrmoy:660F38V06rM",
+ vphsubsw_3 = "rrmoy:660F38V07rM",
+ vpinsrb_4 = "rrri/ood:660F3AV20rMU|rrxi/oob:",
+ vpinsrw_4 = "rrri/ood:660FVC4rMU|rrxi/oow:",
+ vpinsrd_4 = "rrmi/ood:660F3AV22rMU",
+ vpinsrq_4 = "rrmi/ooq:660F3AVX22rMU",
+ vpmaddubsw_3 = "rrmoy:660F38V04rM",
+ vpmaxsb_3 = "rrmoy:660F38V3CrM",
+ vpmaxsd_3 = "rrmoy:660F38V3DrM",
+ vpmaxuw_3 = "rrmoy:660F38V3ErM",
+ vpmaxud_3 = "rrmoy:660F38V3FrM",
+ vpminsb_3 = "rrmoy:660F38V38rM",
+ vpminsd_3 = "rrmoy:660F38V39rM",
+ vpminuw_3 = "rrmoy:660F38V3ArM",
+ vpminud_3 = "rrmoy:660F38V3BrM",
+ vpmovmskb_2 = "rr/do:660FuD7rM|rr/dy:660FuLD7rM",
+ vpmovsxbw_2 = "rroy:660F38u20rM|rx/oq:|rx/yo:",
+ vpmovsxbd_2 = "rroy:660F38u21rM|rx/od:|rx/yq:",
+ vpmovsxbq_2 = "rroy:660F38u22rM|rx/ow:|rx/yd:",
+ vpmovsxwd_2 = "rroy:660F38u23rM|rx/oq:|rx/yo:",
+ vpmovsxwq_2 = "rroy:660F38u24rM|rx/od:|rx/yq:",
+ vpmovsxdq_2 = "rroy:660F38u25rM|rx/oq:|rx/yo:",
+ vpmovzxbw_2 = "rroy:660F38u30rM|rx/oq:|rx/yo:",
+ vpmovzxbd_2 = "rroy:660F38u31rM|rx/od:|rx/yq:",
+ vpmovzxbq_2 = "rroy:660F38u32rM|rx/ow:|rx/yd:",
+ vpmovzxwd_2 = "rroy:660F38u33rM|rx/oq:|rx/yo:",
+ vpmovzxwq_2 = "rroy:660F38u34rM|rx/od:|rx/yq:",
+ vpmovzxdq_2 = "rroy:660F38u35rM|rx/oq:|rx/yo:",
+ vpmuldq_3 = "rrmoy:660F38V28rM",
+ vpmulhrsw_3 = "rrmoy:660F38V0BrM",
+ vpmulld_3 = "rrmoy:660F38V40rM",
+ vpshufb_3 = "rrmoy:660F38V00rM",
+ vpshufd_3 = "rmioy:660Fu70rMU",
+ vpshufhw_3 = "rmioy:F30Fu70rMU",
+ vpshuflw_3 = "rmioy:F20Fu70rMU",
+ vpsignb_3 = "rrmoy:660F38V08rM",
+ vpsignw_3 = "rrmoy:660F38V09rM",
+ vpsignd_3 = "rrmoy:660F38V0ArM",
+ vpslldq_3 = "rrioy:660Fv737mU",
+ vpsllw_3 = "rrmoy:660FVF1rM|rrioy:660Fv716mU",
+ vpslld_3 = "rrmoy:660FVF2rM|rrioy:660Fv726mU",
+ vpsllq_3 = "rrmoy:660FVF3rM|rrioy:660Fv736mU",
+ vpsraw_3 = "rrmoy:660FVE1rM|rrioy:660Fv714mU",
+ vpsrad_3 = "rrmoy:660FVE2rM|rrioy:660Fv724mU",
+ vpsrldq_3 = "rrioy:660Fv733mU",
+ vpsrlw_3 = "rrmoy:660FVD1rM|rrioy:660Fv712mU",
+ vpsrld_3 = "rrmoy:660FVD2rM|rrioy:660Fv722mU",
+ vpsrlq_3 = "rrmoy:660FVD3rM|rrioy:660Fv732mU",
+ vptest_2 = "rmoy:660F38u17rM",
+
+ -- AVX2 integer ops
+ vbroadcasti128_2 = "rx/yo:660F38u5ArM",
+ vinserti128_4 = "rrmi/yyo:660F3AV38rMU",
+ vextracti128_3 = "mri/oy:660F3AuL39RmU",
+ vpblendd_4 = "rrmioy:660F3AV02rMU",
+ vpbroadcastb_2 = "rro:660F38u78rM|rx/ob:|rr/yo:|rx/yb:",
+ vpbroadcastw_2 = "rro:660F38u79rM|rx/ow:|rr/yo:|rx/yw:",
+ vpbroadcastd_2 = "rro:660F38u58rM|rx/od:|rr/yo:|rx/yd:",
+ vpbroadcastq_2 = "rro:660F38u59rM|rx/oq:|rr/yo:|rx/yq:",
+ vpermd_3 = "rrmy:660F38V36rM",
+ vpermq_3 = "rmiy:660F3AuX00rMU",
+ -- *vpgather* (!vsib)
+ vperm2i128_4 = "rrmiy:660F3AV46rMU",
+ vpmaskmovd_3 = "rrxoy:660F38V8CrM|xrroy:660F38V8ERm",
+ vpmaskmovq_3 = "rrxoy:660F38VX8CrM|xrroy:660F38VX8ERm",
+ vpsllvd_3 = "rrmoy:660F38V47rM",
+ vpsllvq_3 = "rrmoy:660F38VX47rM",
+ vpsravd_3 = "rrmoy:660F38V46rM",
+ vpsrlvd_3 = "rrmoy:660F38V45rM",
+ vpsrlvq_3 = "rrmoy:660F38VX45rM",
+
+ -- Intel ADX
+ adcx_2 = "rmqd:660F38F6rM",
+ adox_2 = "rmqd:F30F38F6rM",
+}
+
+------------------------------------------------------------------------------
+
+-- Arithmetic ops.
+for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3,
+ ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do
+ local n8 = shl(n, 3)
+ map_op[name.."_2"] = format(
+ "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi",
+ 1+n8, 3+n8, n, n, 5+n8, n)
+end
+
+-- Shift ops.
+for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3,
+ shl = 4, shr = 5, sar = 7, sal = 4 } do
+ map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n)
+end
+
+-- Conditional ops.
+for cc,n in pairs(map_cc) do
+ map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X
+ map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n)
+ map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+
+end
+
+-- FP arithmetic ops.
+for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3,
+ sub = 4, subr = 5, div = 6, divr = 7 } do
+ local nc = 0xc0 + shl(n, 3)
+ local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8))
+ local fn = "f"..name
+ map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n)
+ if n == 2 or n == 3 then
+ map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n)
+ else
+ map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n)
+ map_op[fn.."p_1"] = format("ff:DE%02Xr", nr)
+ map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr)
+ end
+ map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n)
+end
+
+-- FP conditional moves.
+for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do
+ local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6)
+ map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+
+ map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+
+end
+
+-- SSE / AVX FP arithmetic ops.
+for name,n in pairs{ sqrt = 1, add = 8, mul = 9,
+ sub = 12, min = 13, div = 14, max = 15 } do
+ map_op[name.."ps_2"] = format("rmo:0F5%XrM", n)
+ map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n)
+ map_op[name.."pd_2"] = format("rmo:660F5%XrM", n)
+ map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n)
+ if n ~= 1 then
+ map_op["v"..name.."ps_3"] = format("rrmoy:0FV5%XrM", n)
+ map_op["v"..name.."ss_3"] = format("rrro:F30FV5%XrM|rrx/ood:", n)
+ map_op["v"..name.."pd_3"] = format("rrmoy:660FV5%XrM", n)
+ map_op["v"..name.."sd_3"] = format("rrro:F20FV5%XrM|rrx/ooq:", n)
+ end
+end
+
+-- SSE2 / AVX / AVX2 integer arithmetic ops (66 0F leaf).
+for name,n in pairs{
+ paddb = 0xFC, paddw = 0xFD, paddd = 0xFE, paddq = 0xD4,
+ paddsb = 0xEC, paddsw = 0xED, packssdw = 0x6B,
+ packsswb = 0x63, packuswb = 0x67, paddusb = 0xDC,
+ paddusw = 0xDD, pand = 0xDB, pandn = 0xDF, pavgb = 0xE0,
+ pavgw = 0xE3, pcmpeqb = 0x74, pcmpeqd = 0x76,
+ pcmpeqw = 0x75, pcmpgtb = 0x64, pcmpgtd = 0x66,
+ pcmpgtw = 0x65, pmaddwd = 0xF5, pmaxsw = 0xEE,
+ pmaxub = 0xDE, pminsw = 0xEA, pminub = 0xDA,
+ pmulhuw = 0xE4, pmulhw = 0xE5, pmullw = 0xD5,
+ pmuludq = 0xF4, por = 0xEB, psadbw = 0xF6, psubb = 0xF8,
+ psubw = 0xF9, psubd = 0xFA, psubq = 0xFB, psubsb = 0xE8,
+ psubsw = 0xE9, psubusb = 0xD8, psubusw = 0xD9,
+ punpckhbw = 0x68, punpckhwd = 0x69, punpckhdq = 0x6A,
+ punpckhqdq = 0x6D, punpcklbw = 0x60, punpcklwd = 0x61,
+ punpckldq = 0x62, punpcklqdq = 0x6C, pxor = 0xEF
+} do
+ map_op[name.."_2"] = format("rmo:660F%02XrM", n)
+ map_op["v"..name.."_3"] = format("rrmoy:660FV%02XrM", n)
+end
+
+------------------------------------------------------------------------------
+
+local map_vexarg = { u = false, v = 1, V = 2 }
+
+-- Process pattern string.
+local function dopattern(pat, args, sz, op, needrex)
+ local digit, addin, vex
+ local opcode = 0
+ local szov = sz
+ local narg = 1
+ local rex = 0
+
+ -- Limit number of section buffer positions used by a single dasm_put().
+ -- A single opcode needs a maximum of 6 positions.
+ if secpos+6 > maxsecpos then wflush() end
+
+ -- Process each character.
+ for c in gmatch(pat.."|", ".") do
+ if match(c, "%x") then -- Hex digit.
+ digit = byte(c) - 48
+ if digit > 48 then digit = digit - 39
+ elseif digit > 16 then digit = digit - 7 end
+ opcode = opcode*16 + digit
+ addin = nil
+ elseif c == "n" then -- Disable operand size mods for opcode.
+ szov = nil
+ elseif c == "X" then -- Force REX.W.
+ rex = 8
+ elseif c == "L" then -- Force VEX.L.
+ vex.l = true
+ elseif c == "r" then -- Merge 1st operand regno. into opcode.
+ addin = args[1]; opcode = opcode + (addin.reg % 8)
+ if narg < 2 then narg = 2 end
+ elseif c == "R" then -- Merge 2nd operand regno. into opcode.
+ addin = args[2]; opcode = opcode + (addin.reg % 8)
+ narg = 3
+ elseif c == "m" or c == "M" then -- Encode ModRM/SIB.
+ local s
+ if addin then
+ s = addin.reg
+ opcode = opcode - band(s, 7) -- Undo regno opcode merge.
+ else
+ s = band(opcode, 15) -- Undo last digit.
+ opcode = shr(opcode, 4)
+ end
+ local nn = c == "m" and 1 or 2
+ local t = args[nn]
+ if narg <= nn then narg = nn + 1 end
+ if szov == "q" and rex == 0 then rex = rex + 8 end
+ if t.reg and t.reg > 7 then rex = rex + 1 end
+ if t.xreg and t.xreg > 7 then rex = rex + 2 end
+ if s > 7 then rex = rex + 4 end
+ if needrex then rex = rex + 16 end
+ local psz, sk = wputop(szov, opcode, rex, vex, s < 0, t.vreg or t.vxreg)
+ opcode = nil
+ local imark = sub(pat, -1) -- Force a mark (ugly).
+ -- Put ModRM/SIB with regno/last digit as spare.
+ wputmrmsib(t, imark, s, addin and addin.vreg, psz, sk)
+ addin = nil
+ elseif map_vexarg[c] ~= nil then -- Encode using VEX prefix
+ local b = band(opcode, 255); opcode = shr(opcode, 8)
+ local m = 1
+ if b == 0x38 then m = 2
+ elseif b == 0x3a then m = 3 end
+ if m ~= 1 then b = band(opcode, 255); opcode = shr(opcode, 8) end
+ if b ~= 0x0f then
+ werror("expected `0F', `0F38', or `0F3A' to precede `"..c..
+ "' in pattern `"..pat.."' for `"..op.."'")
+ end
+ local v = map_vexarg[c]
+ if v then v = remove(args, v) end
+ b = band(opcode, 255)
+ local p = 0
+ if b == 0x66 then p = 1
+ elseif b == 0xf3 then p = 2
+ elseif b == 0xf2 then p = 3 end
+ if p ~= 0 then opcode = shr(opcode, 8) end
+ if opcode ~= 0 then wputop(nil, opcode, 0); opcode = 0 end
+ vex = { m = m, p = p, v = v }
+ else
+ if opcode then -- Flush opcode.
+ if szov == "q" and rex == 0 then rex = rex + 8 end
+ if needrex then rex = rex + 16 end
+ if addin and addin.reg == -1 then
+ local psz, sk = wputop(szov, opcode - 7, rex, vex, true)
+ wvreg("opcode", addin.vreg, psz, sk)
+ else
+ if addin and addin.reg > 7 then rex = rex + 1 end
+ wputop(szov, opcode, rex, vex)
+ end
+ opcode = nil
+ end
+ if c == "|" then break end
+ if c == "o" then -- Offset (pure 32 bit displacement).
+ wputdarg(args[1].disp); if narg < 2 then narg = 2 end
+ elseif c == "O" then
+ wputdarg(args[2].disp); narg = 3
+ else
+ -- Anything else is an immediate operand.
+ local a = args[narg]
+ narg = narg + 1
+ local mode, imm = a.mode, a.imm
+ if mode == "iJ" and not match("iIJ", c) then
+ werror("bad operand size for label")
+ end
+ if c == "S" then
+ wputsbarg(imm)
+ elseif c == "U" then
+ wputbarg(imm)
+ elseif c == "W" then
+ wputwarg(imm)
+ elseif c == "i" or c == "I" then
+ if mode == "iJ" then
+ wputlabel("IMM_", imm, 1)
+ elseif mode == "iI" and c == "I" then
+ waction(sz == "w" and "IMM_WB" or "IMM_DB", imm)
+ else
+ wputszarg(sz, imm)
+ end
+ elseif c == "J" then
+ if mode == "iPJ" then
+ waction("REL_A", imm) -- !x64 (secpos)
+ else
+ wputlabel("REL_", imm, 2)
+ end
+ elseif c == "s" then
+ local reg = a.reg
+ if reg < 0 then
+ wputb(0)
+ wvreg("imm.hi", a.vreg)
+ else
+ wputb(shl(reg, 4))
+ end
+ else
+ werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'")
+ end
+ end
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Mapping of operand modes to short names. Suppress output with '#'.
+local map_modename = {
+ r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm",
+ f = "stx", F = "st0", J = "lbl", ["1"] = "1",
+ I = "#", S = "#", O = "#",
+}
+
+-- Return a table/string showing all possible operand modes.
+local function templatehelp(template, nparams)
+ if nparams == 0 then return "" end
+ local t = {}
+ for tm in gmatch(template, "[^%|]+") do
+ local s = map_modename[sub(tm, 1, 1)]
+ s = s..gsub(sub(tm, 2, nparams), ".", function(c)
+ return ", "..map_modename[c]
+ end)
+ if not match(s, "#") then t[#t+1] = s end
+ end
+ return t
+end
+
+-- Match operand modes against mode match part of template.
+local function matchtm(tm, args)
+ for i=1,#args do
+ if not match(args[i].mode, sub(tm, i, i)) then return end
+ end
+ return true
+end
+
+-- Handle opcodes defined with template strings.
+map_op[".template__"] = function(params, template, nparams)
+ if not params then return templatehelp(template, nparams) end
+ local args = {}
+
+ -- Zero-operand opcodes have no match part.
+ if #params == 0 then
+ dopattern(template, args, "d", params.op, nil)
+ return
+ end
+
+ -- Determine common operand size (coerce undefined size) or flag as mixed.
+ local sz, szmix, needrex
+ for i,p in ipairs(params) do
+ args[i] = parseoperand(p)
+ local nsz = args[i].opsize
+ if nsz then
+ if sz and sz ~= nsz then szmix = true else sz = nsz end
+ end
+ local nrex = args[i].needrex
+ if nrex ~= nil then
+ if needrex == nil then
+ needrex = nrex
+ elseif needrex ~= nrex then
+ werror("bad mix of byte-addressable registers")
+ end
+ end
+ end
+
+ -- Try all match:pattern pairs (separated by '|').
+ local gotmatch, lastpat
+ for tm in gmatch(template, "[^%|]+") do
+ -- Split off size match (starts after mode match) and pattern string.
+ local szm, pat = match(tm, "^(.-):(.*)$", #args+1)
+ if pat == "" then pat = lastpat else lastpat = pat end
+ if matchtm(tm, args) then
+ local prefix = sub(szm, 1, 1)
+ if prefix == "/" then -- Exactly match leading operand sizes.
+ for i = #szm,1,-1 do
+ if i == 1 then
+ dopattern(pat, args, sz, params.op, needrex) -- Process pattern.
+ return
+ elseif args[i-1].opsize ~= sub(szm, i, i) then
+ break
+ end
+ end
+ else -- Match common operand size.
+ local szp = sz
+ if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes.
+ if prefix == "1" then szp = args[1].opsize; szmix = nil
+ elseif prefix == "2" then szp = args[2].opsize; szmix = nil end
+ if not szmix and (prefix == "." or match(szm, szp or "#")) then
+ dopattern(pat, args, szp, params.op, needrex) -- Process pattern.
+ return
+ end
+ end
+ gotmatch = true
+ end
+ end
+
+ local msg = "bad operand mode"
+ if gotmatch then
+ if szmix then
+ msg = "mixed operand size"
+ else
+ msg = sz and "bad operand size" or "missing operand size"
+ end
+ end
+
+ werror(msg.." in `"..opmodestr(params.op, args).."'")
+end
+
+------------------------------------------------------------------------------
+
+-- x64-specific opcode for 64 bit immediates and displacements.
+if x64 then
+ function map_op.mov64_2(params)
+ if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end
+ if secpos+2 > maxsecpos then wflush() end
+ local opcode, op64, sz, rex, vreg
+ local op64 = match(params[1], "^%[%s*(.-)%s*%]$")
+ if op64 then
+ local a = parseoperand(params[2])
+ if a.mode ~= "rmR" then werror("bad operand mode") end
+ sz = a.opsize
+ rex = sz == "q" and 8 or 0
+ opcode = 0xa3
+ else
+ op64 = match(params[2], "^%[%s*(.-)%s*%]$")
+ local a = parseoperand(params[1])
+ if op64 then
+ if a.mode ~= "rmR" then werror("bad operand mode") end
+ sz = a.opsize
+ rex = sz == "q" and 8 or 0
+ opcode = 0xa1
+ else
+ if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then
+ werror("bad operand mode")
+ end
+ op64 = params[2]
+ if a.reg == -1 then
+ vreg = a.vreg
+ opcode = 0xb8
+ else
+ opcode = 0xb8 + band(a.reg, 7)
+ end
+ rex = a.reg > 7 and 9 or 8
+ end
+ end
+ local psz, sk = wputop(sz, opcode, rex, nil, vreg)
+ wvreg("opcode", vreg, psz, sk)
+ waction("IMM_D", format("(unsigned int)(%s)", op64))
+ waction("IMM_D", format("(unsigned int)((%s)>>32)", op64))
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcodes for data storage.
+local function op_data(params)
+ if not params then return "imm..." end
+ local sz = sub(params.op, 2, 2)
+ if sz == "a" then sz = addrsize end
+ for _,p in ipairs(params) do
+ local a = parseoperand(p)
+ if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then
+ werror("bad mode or size in `"..p.."'")
+ end
+ if a.mode == "iJ" then
+ wputlabel("IMM_", a.imm, 1)
+ else
+ wputszarg(sz, a.imm)
+ end
+ if secpos+2 > maxsecpos then wflush() end
+ end
+end
+
+map_op[".byte_*"] = op_data
+map_op[".sbyte_*"] = op_data
+map_op[".word_*"] = op_data
+map_op[".dword_*"] = op_data
+map_op[".aword_*"] = op_data
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode to mark the position where the action list is to be emitted.
+map_op[".actionlist_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeactions(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the global enum is to be emitted.
+map_op[".globals_1"] = function(params)
+ if not params then return "prefix" end
+ local prefix = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobals(out, prefix) end)
+end
+
+-- Pseudo-opcode to mark the position where the global names are to be emitted.
+map_op[".globalnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeglobalnames(out, name) end)
+end
+
+-- Pseudo-opcode to mark the position where the extern names are to be emitted.
+map_op[".externnames_1"] = function(params)
+ if not params then return "cvar" end
+ local name = params[1] -- No syntax check. You get to keep the pieces.
+ wline(function(out) writeexternnames(out, name) end)
+end
+
+------------------------------------------------------------------------------
+
+-- Label pseudo-opcode (converted from trailing colon form).
+map_op[".label_2"] = function(params)
+ if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end
+ if secpos+2 > maxsecpos then wflush() end
+ local a = parseoperand(params[1])
+ local mode, imm = a.mode, a.imm
+ if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then
+ -- Local label (1: ... 9:) or global label (->global:).
+ waction("LABEL_LG", nil, 1)
+ wputxb(imm)
+ elseif mode == "iJ" then
+ -- PC label (=>pcexpr:).
+ waction("LABEL_PC", imm)
+ else
+ werror("bad label definition")
+ end
+ -- SETLABEL must immediately follow LABEL_LG/LABEL_PC.
+ local addr = params[2]
+ if addr then
+ local a = parseoperand(addr)
+ if a.mode == "iPJ" then
+ waction("SETLABEL", a.imm)
+ else
+ werror("bad label assignment")
+ end
+ end
+end
+map_op[".label_1"] = map_op[".label_2"]
+
+------------------------------------------------------------------------------
+
+-- Alignment pseudo-opcode.
+map_op[".align_1"] = function(params)
+ if not params then return "numpow2" end
+ if secpos+1 > maxsecpos then wflush() end
+ local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]]
+ if align then
+ local x = align
+ -- Must be a power of 2 in the range (2 ... 256).
+ for i=1,8 do
+ x = x / 2
+ if x == 1 then
+ waction("ALIGN", nil, 1)
+ wputxb(align-1) -- Action byte is 2**n-1.
+ return
+ end
+ end
+ end
+ werror("bad alignment")
+end
+
+-- Spacing pseudo-opcode.
+map_op[".space_2"] = function(params)
+ if not params then return "num [, filler]" end
+ if secpos+1 > maxsecpos then wflush() end
+ waction("SPACE", params[1])
+ local fill = params[2]
+ if fill then
+ fill = tonumber(fill)
+ if not fill or fill < 0 or fill > 255 then werror("bad filler") end
+ end
+ wputxb(fill or 0)
+end
+map_op[".space_1"] = map_op[".space_2"]
+
+------------------------------------------------------------------------------
+
+-- Pseudo-opcode for (primitive) type definitions (map to C types).
+map_op[".type_3"] = function(params, nparams)
+ if not params then
+ return nparams == 2 and "name, ctype" or "name, ctype, reg"
+ end
+ local name, ctype, reg = params[1], params[2], params[3]
+ if not match(name, "^[%a_][%w_]*$") then
+ werror("bad type name `"..name.."'")
+ end
+ local tp = map_type[name]
+ if tp then
+ werror("duplicate type `"..name.."'")
+ end
+ if reg and not map_reg_valid_base[reg] then
+ werror("bad base register `"..(map_reg_rev[reg] or reg).."'")
+ end
+ -- Add #type to defines. A bit unclean to put it in map_archdef.
+ map_archdef["#"..name] = "sizeof("..ctype..")"
+ -- Add new type and emit shortcut define.
+ local num = ctypenum + 1
+ map_type[name] = {
+ ctype = ctype,
+ ctypefmt = format("Dt%X(%%s)", num),
+ reg = reg,
+ }
+ wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype))
+ ctypenum = num
+end
+map_op[".type_2"] = map_op[".type_3"]
+
+-- Dump type definitions.
+local function dumptypes(out, lvl)
+ local t = {}
+ for name in pairs(map_type) do t[#t+1] = name end
+ sort(t)
+ out:write("Type definitions:\n")
+ for _,name in ipairs(t) do
+ local tp = map_type[name]
+ local reg = tp.reg and map_reg_rev[tp.reg] or ""
+ out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Set the current section.
+function _M.section(num)
+ waction("SECTION")
+ wputxb(num)
+ wflush(true) -- SECTION is a terminal action.
+end
+
+------------------------------------------------------------------------------
+
+-- Dump architecture description.
+function _M.dumparch(out)
+ out:write(format("DynASM %s version %s, released %s\n\n",
+ _info.arch, _info.version, _info.release))
+ dumpregs(out)
+ dumpactions(out)
+end
+
+-- Dump all user defined elements.
+function _M.dumpdef(out, lvl)
+ dumptypes(out, lvl)
+ dumpglobals(out, lvl)
+ dumpexterns(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Pass callbacks from/to the DynASM core.
+function _M.passcb(wl, we, wf, ww)
+ wline, werror, wfatal, wwarn = wl, we, wf, ww
+ return wflush
+end
+
+-- Setup the arch-specific module.
+function _M.setup(arch, opt)
+ g_arch, g_opt = arch, opt
+end
+
+-- Merge the core maps and the arch-specific maps.
+function _M.mergemaps(map_coreop, map_def)
+ setmetatable(map_op, { __index = map_coreop })
+ setmetatable(map_def, { __index = map_archdef })
+ return map_op, map_def
+end
+
+return _M
+
+------------------------------------------------------------------------------
+
diff --git a/ext/opcache/jit/dynasm/dynasm.lua b/ext/opcache/jit/dynasm/dynasm.lua
new file mode 100644
index 0000000000..b7ac453cbd
--- /dev/null
+++ b/ext/opcache/jit/dynasm/dynasm.lua
@@ -0,0 +1,1094 @@
+------------------------------------------------------------------------------
+-- DynASM. A dynamic assembler for code generation engines.
+-- Originally designed and implemented for LuaJIT.
+--
+-- Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+-- See below for full copyright notice.
+------------------------------------------------------------------------------
+
+-- Application information.
+local _info = {
+ name = "DynASM",
+ description = "A dynamic assembler for code generation engines",
+ version = "1.4.0",
+ vernum = 10400,
+ release = "2015-10-18",
+ author = "Mike Pall",
+ url = "http://luajit.org/dynasm.html",
+ license = "MIT",
+ copyright = [[
+Copyright (C) 2005-2016 Mike Pall. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+[ MIT license: http://www.opensource.org/licenses/mit-license.php ]
+]],
+}
+
+-- Cache library functions.
+local type, pairs, ipairs = type, pairs, ipairs
+local pcall, error, assert = pcall, error, assert
+local _s = string
+local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub
+local format, rep, upper = _s.format, _s.rep, _s.upper
+local _t = table
+local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort
+local exit = os.exit
+local io = io
+local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr
+
+------------------------------------------------------------------------------
+
+-- Program options.
+local g_opt = {}
+
+-- Global state for current file.
+local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch
+local g_errcount = 0
+
+-- Write buffer for output file.
+local g_wbuffer, g_capbuffer
+
+------------------------------------------------------------------------------
+
+-- Write an output line (or callback function) to the buffer.
+local function wline(line, needindent)
+ local buf = g_capbuffer or g_wbuffer
+ buf[#buf+1] = needindent and g_indent..line or line
+ g_synclineno = g_synclineno + 1
+end
+
+-- Write assembler line as a comment, if requested.
+local function wcomment(aline)
+ if g_opt.comment then
+ wline(g_opt.comment..aline..g_opt.endcomment, true)
+ end
+end
+
+-- Resync CPP line numbers.
+local function wsync()
+ if g_synclineno ~= g_lineno and g_opt.cpp then
+ wline("#line "..g_lineno..' "'..g_fname..'"')
+ g_synclineno = g_lineno
+ end
+end
+
+-- Dummy action flush function. Replaced with arch-specific function later.
+local function wflush(term)
+end
+
+-- Dump all buffered output lines.
+local function wdumplines(out, buf)
+ for _,line in ipairs(buf) do
+ if type(line) == "string" then
+ assert(out:write(line, "\n"))
+ else
+ -- Special callback to dynamically insert lines after end of processing.
+ line(out)
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Emit an error. Processing continues with next statement.
+local function werror(msg)
+ error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0)
+end
+
+-- Emit a fatal error. Processing stops.
+local function wfatal(msg)
+ g_errcount = "fatal"
+ werror(msg)
+end
+
+-- Print a warning. Processing continues.
+local function wwarn(msg)
+ stderr:write(format("%s:%s: warning: %s:\n%s\n",
+ g_fname, g_lineno, msg, g_curline))
+end
+
+-- Print caught error message. But suppress excessive errors.
+local function wprinterr(...)
+ if type(g_errcount) == "number" then
+ -- Regular error.
+ g_errcount = g_errcount + 1
+ if g_errcount < 21 then -- Seems to be a reasonable limit.
+ stderr:write(...)
+ elseif g_errcount == 21 then
+ stderr:write(g_fname,
+ ":*: warning: too many errors (suppressed further messages).\n")
+ end
+ else
+ -- Fatal error.
+ stderr:write(...)
+ return true -- Stop processing.
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Map holding all option handlers.
+local opt_map = {}
+local opt_current
+
+-- Print error and exit with error status.
+local function opterror(...)
+ stderr:write("dynasm.lua: ERROR: ", ...)
+ stderr:write("\n")
+ exit(1)
+end
+
+-- Get option parameter.
+local function optparam(args)
+ local argn = args.argn
+ local p = args[argn]
+ if not p then
+ opterror("missing parameter for option `", opt_current, "'.")
+ end
+ args.argn = argn + 1
+ return p
+end
+
+------------------------------------------------------------------------------
+
+-- Core pseudo-opcodes.
+local map_coreop = {}
+-- Dummy opcode map. Replaced by arch-specific map.
+local map_op = {}
+
+-- Forward declarations.
+local dostmt
+local readfile
+
+------------------------------------------------------------------------------
+
+-- Map for defines (initially empty, chains to arch-specific map).
+local map_def = {}
+
+-- Pseudo-opcode to define a substitution.
+map_coreop[".define_2"] = function(params, nparams)
+ if not params then return nparams == 1 and "name" or "name, subst" end
+ local name, def = params[1], params[2] or "1"
+ if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end
+ map_def[name] = def
+end
+map_coreop[".define_1"] = map_coreop[".define_2"]
+
+-- Define a substitution on the command line.
+function opt_map.D(args)
+ local namesubst = optparam(args)
+ local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$")
+ if name then
+ map_def[name] = subst
+ elseif match(namesubst, "^[%a_][%w_]*$") then
+ map_def[namesubst] = "1"
+ else
+ opterror("bad define")
+ end
+end
+
+-- Undefine a substitution on the command line.
+function opt_map.U(args)
+ local name = optparam(args)
+ if match(name, "^[%a_][%w_]*$") then
+ map_def[name] = nil
+ else
+ opterror("bad define")
+ end
+end
+
+-- Helper for definesubst.
+local gotsubst
+
+local function definesubst_one(word)
+ local subst = map_def[word]
+ if subst then gotsubst = word; return subst else return word end
+end
+
+-- Iteratively substitute defines.
+local function definesubst(stmt)
+ -- Limit number of iterations.
+ for i=1,100 do
+ gotsubst = false
+ stmt = gsub(stmt, "#?[%w_]+", definesubst_one)
+ if not gotsubst then break end
+ end
+ if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end
+ return stmt
+end
+
+-- Dump all defines.
+local function dumpdefines(out, lvl)
+ local t = {}
+ for name in pairs(map_def) do
+ t[#t+1] = name
+ end
+ sort(t)
+ out:write("Defines:\n")
+ for _,name in ipairs(t) do
+ local subst = map_def[name]
+ if g_arch then subst = g_arch.revdef(subst) end
+ out:write(format(" %-20s %s\n", name, subst))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Support variables for conditional assembly.
+local condlevel = 0
+local condstack = {}
+
+-- Evaluate condition with a Lua expression. Substitutions already performed.
+local function cond_eval(cond)
+ local func, err
+ if setfenv then
+ func, err = loadstring("return "..cond, "=expr")
+ else
+ -- No globals. All unknown identifiers evaluate to nil.
+ func, err = load("return "..cond, "=expr", "t", {})
+ end
+ if func then
+ if setfenv then
+ setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil.
+ end
+ local ok, res = pcall(func)
+ if ok then
+ if res == 0 then return false end -- Oh well.
+ return not not res
+ end
+ err = res
+ end
+ wfatal("bad condition: "..err)
+end
+
+-- Skip statements until next conditional pseudo-opcode at the same level.
+local function stmtskip()
+ local dostmt_save = dostmt
+ local lvl = 0
+ dostmt = function(stmt)
+ local op = match(stmt, "^%s*(%S+)")
+ if op == ".if" then
+ lvl = lvl + 1
+ elseif lvl ~= 0 then
+ if op == ".endif" then lvl = lvl - 1 end
+ elseif op == ".elif" or op == ".else" or op == ".endif" then
+ dostmt = dostmt_save
+ dostmt(stmt)
+ end
+ end
+end
+
+-- Pseudo-opcodes for conditional assembly.
+map_coreop[".if_1"] = function(params)
+ if not params then return "condition" end
+ local lvl = condlevel + 1
+ local res = cond_eval(params[1])
+ condlevel = lvl
+ condstack[lvl] = res
+ if not res then stmtskip() end
+end
+
+map_coreop[".elif_1"] = function(params)
+ if not params then return "condition" end
+ if condlevel == 0 then wfatal(".elif without .if") end
+ local lvl = condlevel
+ local res = condstack[lvl]
+ if res then
+ if res == "else" then wfatal(".elif after .else") end
+ else
+ res = cond_eval(params[1])
+ if res then
+ condstack[lvl] = res
+ return
+ end
+ end
+ stmtskip()
+end
+
+map_coreop[".else_0"] = function(params)
+ if condlevel == 0 then wfatal(".else without .if") end
+ local lvl = condlevel
+ local res = condstack[lvl]
+ condstack[lvl] = "else"
+ if res then
+ if res == "else" then wfatal(".else after .else") end
+ stmtskip()
+ end
+end
+
+map_coreop[".endif_0"] = function(params)
+ local lvl = condlevel
+ if lvl == 0 then wfatal(".endif without .if") end
+ condlevel = lvl - 1
+end
+
+-- Check for unfinished conditionals.
+local function checkconds()
+ if g_errcount ~= "fatal" and condlevel ~= 0 then
+ wprinterr(g_fname, ":*: error: unbalanced conditional\n")
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Search for a file in the given path and open it for reading.
+local function pathopen(path, name)
+ local dirsep = package and match(package.path, "\\") and "\\" or "/"
+ for _,p in ipairs(path) do
+ local fullname = p == "" and name or p..dirsep..name
+ local fin = io.open(fullname, "r")
+ if fin then
+ g_fname = fullname
+ return fin
+ end
+ end
+end
+
+-- Include a file.
+map_coreop[".include_1"] = function(params)
+ if not params then return "filename" end
+ local name = params[1]
+ -- Save state. Ugly, I know. but upvalues are fast.
+ local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent
+ -- Read the included file.
+ local fatal = readfile(pathopen(g_opt.include, name) or
+ wfatal("include file `"..name.."' not found"))
+ -- Restore state.
+ g_synclineno = -1
+ g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi
+ if fatal then wfatal("in include file") end
+end
+
+-- Make .include and conditionals initially available, too.
+map_op[".include_1"] = map_coreop[".include_1"]
+map_op[".if_1"] = map_coreop[".if_1"]
+map_op[".elif_1"] = map_coreop[".elif_1"]
+map_op[".else_0"] = map_coreop[".else_0"]
+map_op[".endif_0"] = map_coreop[".endif_0"]
+
+------------------------------------------------------------------------------
+
+-- Support variables for macros.
+local mac_capture, mac_lineno, mac_name
+local mac_active = {}
+local mac_list = {}
+
+-- Pseudo-opcode to define a macro.
+map_coreop[".macro_*"] = function(mparams)
+ if not mparams then return "name [, params...]" end
+ -- Split off and validate macro name.
+ local name = remove(mparams, 1)
+ if not name then werror("missing macro name") end
+ if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then
+ wfatal("bad macro name `"..name.."'")
+ end
+ -- Validate macro parameter names.
+ local mdup = {}
+ for _,mp in ipairs(mparams) do
+ if not match(mp, "^[%a_][%w_]*$") then
+ wfatal("bad macro parameter name `"..mp.."'")
+ end
+ if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end
+ mdup[mp] = true
+ end
+ -- Check for duplicate or recursive macro definitions.
+ local opname = name.."_"..#mparams
+ if map_op[opname] or map_op[name.."_*"] then
+ wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)")
+ end
+ if mac_capture then wfatal("recursive macro definition") end
+
+ -- Enable statement capture.
+ local lines = {}
+ mac_lineno = g_lineno
+ mac_name = name
+ mac_capture = function(stmt) -- Statement capture function.
+ -- Stop macro definition with .endmacro pseudo-opcode.
+ if not match(stmt, "^%s*.endmacro%s*$") then
+ lines[#lines+1] = stmt
+ return
+ end
+ mac_capture = nil
+ mac_lineno = nil
+ mac_name = nil
+ mac_list[#mac_list+1] = opname
+ -- Add macro-op definition.
+ map_op[opname] = function(params)
+ if not params then return mparams, lines end
+ -- Protect against recursive macro invocation.
+ if mac_active[opname] then wfatal("recursive macro invocation") end
+ mac_active[opname] = true
+ -- Setup substitution map.
+ local subst = {}
+ for i,mp in ipairs(mparams) do subst[mp] = params[i] end
+ local mcom
+ if g_opt.maccomment and g_opt.comment then
+ mcom = " MACRO "..name.." ("..#mparams..")"
+ wcomment("{"..mcom)
+ end
+ -- Loop through all captured statements
+ for _,stmt in ipairs(lines) do
+ -- Substitute macro parameters.
+ local st = gsub(stmt, "[%w_]+", subst)
+ st = definesubst(st)
+ st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b.
+ if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end
+ -- Emit statement. Use a protected call for better diagnostics.
+ local ok, err = pcall(dostmt, st)
+ if not ok then
+ -- Add the captured statement to the error.
+ wprinterr(err, "\n", g_indent, "| ", stmt,
+ "\t[MACRO ", name, " (", #mparams, ")]\n")
+ end
+ end
+ if mcom then wcomment("}"..mcom) end
+ mac_active[opname] = nil
+ end
+ end
+end
+
+-- An .endmacro pseudo-opcode outside of a macro definition is an error.
+map_coreop[".endmacro_0"] = function(params)
+ wfatal(".endmacro without .macro")
+end
+
+-- Dump all macros and their contents (with -PP only).
+local function dumpmacros(out, lvl)
+ sort(mac_list)
+ out:write("Macros:\n")
+ for _,opname in ipairs(mac_list) do
+ local name = sub(opname, 1, -3)
+ local params, lines = map_op[opname]()
+ out:write(format(" %-20s %s\n", name, concat(params, ", ")))
+ if lvl > 1 then
+ for _,line in ipairs(lines) do
+ out:write(" |", line, "\n")
+ end
+ out:write("\n")
+ end
+ end
+ out:write("\n")
+end
+
+-- Check for unfinished macro definitions.
+local function checkmacros()
+ if mac_capture then
+ wprinterr(g_fname, ":", mac_lineno,
+ ": error: unfinished .macro `", mac_name ,"'\n")
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Support variables for captures.
+local cap_lineno, cap_name
+local cap_buffers = {}
+local cap_used = {}
+
+-- Start a capture.
+map_coreop[".capture_1"] = function(params)
+ if not params then return "name" end
+ wflush()
+ local name = params[1]
+ if not match(name, "^[%a_][%w_]*$") then
+ wfatal("bad capture name `"..name.."'")
+ end
+ if cap_name then
+ wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno)
+ end
+ cap_name = name
+ cap_lineno = g_lineno
+ -- Create or continue a capture buffer and start the output line capture.
+ local buf = cap_buffers[name]
+ if not buf then buf = {}; cap_buffers[name] = buf end
+ g_capbuffer = buf
+ g_synclineno = 0
+end
+
+-- Stop a capture.
+map_coreop[".endcapture_0"] = function(params)
+ wflush()
+ if not cap_name then wfatal(".endcapture without a valid .capture") end
+ cap_name = nil
+ cap_lineno = nil
+ g_capbuffer = nil
+ g_synclineno = 0
+end
+
+-- Dump a capture buffer.
+map_coreop[".dumpcapture_1"] = function(params)
+ if not params then return "name" end
+ wflush()
+ local name = params[1]
+ if not match(name, "^[%a_][%w_]*$") then
+ wfatal("bad capture name `"..name.."'")
+ end
+ cap_used[name] = true
+ wline(function(out)
+ local buf = cap_buffers[name]
+ if buf then wdumplines(out, buf) end
+ end)
+ g_synclineno = 0
+end
+
+-- Dump all captures and their buffers (with -PP only).
+local function dumpcaptures(out, lvl)
+ out:write("Captures:\n")
+ for name,buf in pairs(cap_buffers) do
+ out:write(format(" %-20s %4s)\n", name, "("..#buf))
+ if lvl > 1 then
+ local bar = rep("=", 76)
+ out:write(" ", bar, "\n")
+ for _,line in ipairs(buf) do
+ out:write(" ", line, "\n")
+ end
+ out:write(" ", bar, "\n\n")
+ end
+ end
+ out:write("\n")
+end
+
+-- Check for unfinished or unused captures.
+local function checkcaptures()
+ if cap_name then
+ wprinterr(g_fname, ":", cap_lineno,
+ ": error: unfinished .capture `", cap_name,"'\n")
+ return
+ end
+ for name in pairs(cap_buffers) do
+ if not cap_used[name] then
+ wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n")
+ end
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Sections names.
+local map_sections = {}
+
+-- Pseudo-opcode to define code sections.
+-- TODO: Data sections, BSS sections. Needs extra C code and API.
+map_coreop[".section_*"] = function(params)
+ if not params then return "name..." end
+ if #map_sections > 0 then werror("duplicate section definition") end
+ wflush()
+ for sn,name in ipairs(params) do
+ local opname = "."..name.."_0"
+ if not match(name, "^[%a][%w_]*$") or
+ map_op[opname] or map_op["."..name.."_*"] then
+ werror("bad section name `"..name.."'")
+ end
+ map_sections[#map_sections+1] = name
+ wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1))
+ map_op[opname] = function(params) g_arch.section(sn-1) end
+ end
+ wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections))
+end
+
+-- Dump all sections.
+local function dumpsections(out, lvl)
+ out:write("Sections:\n")
+ for _,name in ipairs(map_sections) do
+ out:write(format(" %s\n", name))
+ end
+ out:write("\n")
+end
+
+------------------------------------------------------------------------------
+
+-- Replacement for customized Lua, which lacks the package library.
+local prefix = ""
+if not require then
+ function require(name)
+ local fp = assert(io.open(prefix..name..".lua"))
+ local s = fp:read("*a")
+ assert(fp:close())
+ return assert(loadstring(s, "@"..name..".lua"))()
+ end
+end
+
+-- Load architecture-specific module.
+local function loadarch(arch)
+ if not match(arch, "^[%w_]+$") then return "bad arch name" end
+ local ok, m_arch = pcall(require, "dasm_"..arch)
+ if not ok then return "cannot load module: "..m_arch end
+ g_arch = m_arch
+ wflush = m_arch.passcb(wline, werror, wfatal, wwarn)
+ m_arch.setup(arch, g_opt)
+ map_op, map_def = m_arch.mergemaps(map_coreop, map_def)
+end
+
+-- Dump architecture description.
+function opt_map.dumparch(args)
+ local name = optparam(args)
+ if not g_arch then
+ local err = loadarch(name)
+ if err then opterror(err) end
+ end
+
+ local t = {}
+ for name in pairs(map_coreop) do t[#t+1] = name end
+ for name in pairs(map_op) do t[#t+1] = name end
+ sort(t)
+
+ local out = stdout
+ local _arch = g_arch._info
+ out:write(format("%s version %s, released %s, %s\n",
+ _info.name, _info.version, _info.release, _info.url))
+ g_arch.dumparch(out)
+
+ local pseudo = true
+ out:write("Pseudo-Opcodes:\n")
+ for _,sname in ipairs(t) do
+ local name, nparam = match(sname, "^(.+)_([0-9%*])$")
+ if name then
+ if pseudo and sub(name, 1, 1) ~= "." then
+ out:write("\nOpcodes:\n")
+ pseudo = false
+ end
+ local f = map_op[sname]
+ local s
+ if nparam ~= "*" then nparam = nparam + 0 end
+ if nparam == 0 then
+ s = ""
+ elseif type(f) == "string" then
+ s = map_op[".template__"](nil, f, nparam)
+ else
+ s = f(nil, nparam)
+ end
+ if type(s) == "table" then
+ for _,s2 in ipairs(s) do
+ out:write(format(" %-12s %s\n", name, s2))
+ end
+ else
+ out:write(format(" %-12s %s\n", name, s))
+ end
+ end
+ end
+ out:write("\n")
+ exit(0)
+end
+
+-- Pseudo-opcode to set the architecture.
+-- Only initially available (map_op is replaced when called).
+map_op[".arch_1"] = function(params)
+ if not params then return "name" end
+ local err = loadarch(params[1])
+ if err then wfatal(err) end
+ wline(format("#if DASM_VERSION != %d", _info.vernum))
+ wline('#error "Version mismatch between DynASM and included encoding engine"')
+ wline("#endif")
+end
+
+-- Dummy .arch pseudo-opcode to improve the error report.
+map_coreop[".arch_1"] = function(params)
+ if not params then return "name" end
+ wfatal("duplicate .arch statement")
+end
+
+------------------------------------------------------------------------------
+
+-- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
+map_coreop[".nop_*"] = function(params)
+ if not params then return "[ignored...]" end
+end
+
+-- Pseudo-opcodes to raise errors.
+map_coreop[".error_1"] = function(params)
+ if not params then return "message" end
+ werror(params[1])
+end
+
+map_coreop[".fatal_1"] = function(params)
+ if not params then return "message" end
+ wfatal(params[1])
+end
+
+-- Dump all user defined elements.
+local function dumpdef(out)
+ local lvl = g_opt.dumpdef
+ if lvl == 0 then return end
+ dumpsections(out, lvl)
+ dumpdefines(out, lvl)
+ if g_arch then g_arch.dumpdef(out, lvl) end
+ dumpmacros(out, lvl)
+ dumpcaptures(out, lvl)
+end
+
+------------------------------------------------------------------------------
+
+-- Helper for splitstmt.
+local splitlvl
+
+local function splitstmt_one(c)
+ if c == "(" then
+ splitlvl = ")"..splitlvl
+ elseif c == "[" then
+ splitlvl = "]"..splitlvl
+ elseif c == "{" then
+ splitlvl = "}"..splitlvl
+ elseif c == ")" or c == "]" or c == "}" then
+ if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end
+ splitlvl = sub(splitlvl, 2)
+ elseif splitlvl == "" then
+ return " \0 "
+ end
+ return c
+end
+
+-- Split statement into (pseudo-)opcode and params.
+local function splitstmt(stmt)
+ -- Convert label with trailing-colon into .label statement.
+ local label = match(stmt, "^%s*(.+):%s*$")
+ if label then return ".label", {label} end
+
+ -- Split at commas and equal signs, but obey parentheses and brackets.
+ splitlvl = ""
+ stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one)
+ if splitlvl ~= "" then werror("unbalanced () or []") end
+
+ -- Split off opcode.
+ local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$")
+ if not op then werror("bad statement syntax") end
+
+ -- Split parameters.
+ local params = {}
+ for p in gmatch(other, "%s*(%Z+)%z?") do
+ params[#params+1] = gsub(p, "%s+$", "")
+ end
+ if #params > 16 then werror("too many parameters") end
+
+ params.op = op
+ return op, params
+end
+
+-- Process a single statement.
+dostmt = function(stmt)
+ -- Ignore empty statements.
+ if match(stmt, "^%s*$") then return end
+
+ -- Capture macro defs before substitution.
+ if mac_capture then return mac_capture(stmt) end
+ stmt = definesubst(stmt)
+
+ -- Emit C code without parsing the line.
+ if sub(stmt, 1, 1) == "|" then
+ local tail = sub(stmt, 2)
+ wflush()
+ if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end
+ return
+ end
+
+ -- Split into (pseudo-)opcode and params.
+ local op, params = splitstmt(stmt)
+
+ -- Get opcode handler (matching # of parameters or generic handler).
+ local f = map_op[op.."_"..#params] or map_op[op.."_*"]
+ if not f then
+ if not g_arch then wfatal("first statement must be .arch") end
+ -- Improve error report.
+ for i=0,9 do
+ if map_op[op.."_"..i] then
+ werror("wrong number of parameters for `"..op.."'")
+ end
+ end
+ werror("unknown statement `"..op.."'")
+ end
+
+ -- Call opcode handler or special handler for template strings.
+ if type(f) == "string" then
+ map_op[".template__"](params, f)
+ else
+ f(params)
+ end
+end
+
+-- Process a single line.
+local function doline(line)
+ if g_opt.flushline then wflush() end
+
+ -- Assembler line?
+ local indent, aline = match(line, "^(%s*)%|(.*)$")
+ if not aline then
+ -- No, plain C code line, need to flush first.
+ wflush()
+ wsync()
+ wline(line, false)
+ return
+ end
+
+ g_indent = indent -- Remember current line indentation.
+
+ -- Emit C code (even from macros). Avoids echo and line parsing.
+ if sub(aline, 1, 1) == "|" then
+ if not mac_capture then
+ wsync()
+ elseif g_opt.comment then
+ wsync()
+ wcomment(aline)
+ end
+ dostmt(aline)
+ return
+ end
+
+ -- Echo assembler line as a comment.
+ if g_opt.comment then
+ wsync()
+ wcomment(aline)
+ end
+
+ -- Strip assembler comments.
+ aline = gsub(aline, "//.*$", "")
+
+ -- Split line into statements at semicolons.
+ if match(aline, ";") then
+ for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end
+ else
+ dostmt(aline)
+ end
+end
+
+------------------------------------------------------------------------------
+
+-- Write DynASM header.
+local function dasmhead(out)
+ out:write(format([[
+/*
+** This file has been pre-processed with DynASM.
+** %s
+** DynASM version %s, DynASM %s version %s
+** DO NOT EDIT! The original file is in "%s".
+*/
+
+]], _info.url,
+ _info.version, g_arch._info.arch, g_arch._info.version,
+ g_fname))
+end
+
+-- Read input file.
+readfile = function(fin)
+ g_indent = ""
+ g_lineno = 0
+ g_synclineno = -1
+
+ -- Process all lines.
+ for line in fin:lines() do
+ g_lineno = g_lineno + 1
+ g_curline = line
+ local ok, err = pcall(doline, line)
+ if not ok and wprinterr(err, "\n") then return true end
+ end
+ wflush()
+
+ -- Close input file.
+ assert(fin == stdin or fin:close())
+end
+
+-- Write output file.
+local function writefile(outfile)
+ local fout
+
+ -- Open output file.
+ if outfile == nil or outfile == "-" then
+ fout = stdout
+ else
+ fout = assert(io.open(outfile, "w"))
+ end
+
+ -- Write all buffered lines
+ wdumplines(fout, g_wbuffer)
+
+ -- Close output file.
+ assert(fout == stdout or fout:close())
+
+ -- Optionally dump definitions.
+ dumpdef(fout == stdout and stderr or stdout)
+end
+
+-- Translate an input file to an output file.
+local function translate(infile, outfile)
+ g_wbuffer = {}
+ g_indent = ""
+ g_lineno = 0
+ g_synclineno = -1
+
+ -- Put header.
+ wline(dasmhead)
+
+ -- Read input file.
+ local fin
+ if infile == "-" then
+ g_fname = "(stdin)"
+ fin = stdin
+ else
+ g_fname = infile
+ fin = assert(io.open(infile, "r"))
+ end
+ readfile(fin)
+
+ -- Check for errors.
+ if not g_arch then
+ wprinterr(g_fname, ":*: error: missing .arch directive\n")
+ end
+ checkconds()
+ checkmacros()
+ checkcaptures()
+
+ if g_errcount ~= 0 then
+ stderr:write(g_fname, ":*: info: ", g_errcount, " error",
+ (type(g_errcount) == "number" and g_errcount > 1) and "s" or "",
+ " in input file -- no output file generated.\n")
+ dumpdef(stderr)
+ exit(1)
+ end
+
+ -- Write output file.
+ writefile(outfile)
+end
+
+------------------------------------------------------------------------------
+
+-- Print help text.
+function opt_map.help()
+ stdout:write("DynASM -- ", _info.description, ".\n")
+ stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n")
+ stdout:write[[
+
+Usage: dynasm [OPTION]... INFILE.dasc|-
+
+ -h, --help Display this help text.
+ -V, --version Display version and copyright information.
+
+ -o, --outfile FILE Output file name (default is stdout).
+ -I, --include DIR Add directory to the include search path.
+
+ -c, --ccomment Use /* */ comments for assembler lines.
+ -C, --cppcomment Use // comments for assembler lines (default).
+ -N, --nocomment Suppress assembler lines in output.
+ -M, --maccomment Show macro expansions as comments (default off).
+
+ -L, --nolineno Suppress CPP line number information in output.
+ -F, --flushline Flush action list for every line.
+
+ -D NAME[=SUBST] Define a substitution.
+ -U NAME Undefine a substitution.
+
+ -P, --dumpdef Dump defines, macros, etc. Repeat for more output.
+ -A, --dumparch ARCH Load architecture ARCH and dump description.
+]]
+ exit(0)
+end
+
+-- Print version information.
+function opt_map.version()
+ stdout:write(format("%s version %s, released %s\n%s\n\n%s",
+ _info.name, _info.version, _info.release, _info.url, _info.copyright))
+ exit(0)
+end
+
+-- Misc. options.
+function opt_map.outfile(args) g_opt.outfile = optparam(args) end
+function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end
+function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end
+function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end
+function opt_map.nocomment() g_opt.comment = false end
+function opt_map.maccomment() g_opt.maccomment = true end
+function opt_map.nolineno() g_opt.cpp = false end
+function opt_map.flushline() g_opt.flushline = true end
+function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end
+
+------------------------------------------------------------------------------
+
+-- Short aliases for long options.
+local opt_alias = {
+ h = "help", ["?"] = "help", V = "version",
+ o = "outfile", I = "include",
+ c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment",
+ L = "nolineno", F = "flushline",
+ P = "dumpdef", A = "dumparch",
+}
+
+-- Parse single option.
+local function parseopt(opt, args)
+ opt_current = #opt == 1 and "-"..opt or "--"..opt
+ local f = opt_map[opt] or opt_map[opt_alias[opt]]
+ if not f then
+ opterror("unrecognized option `", opt_current, "'. Try `--help'.\n")
+ end
+ f(args)
+end
+
+-- Parse arguments.
+local function parseargs(args)
+ -- Default options.
+ g_opt.comment = "//|"
+ g_opt.endcomment = ""
+ g_opt.cpp = true
+ g_opt.dumpdef = 0
+ g_opt.include = { "" }
+
+ -- Process all option arguments.
+ args.argn = 1
+ repeat
+ local a = args[args.argn]
+ if not a then break end
+ local lopt, opt = match(a, "^%-(%-?)(.+)")
+ if not opt then break end
+ args.argn = args.argn + 1
+ if lopt == "" then
+ -- Loop through short options.
+ for o in gmatch(opt, ".") do parseopt(o, args) end
+ else
+ -- Long option.
+ parseopt(opt, args)
+ end
+ until false
+
+ -- Check for proper number of arguments.
+ local nargs = #args - args.argn + 1
+ if nargs ~= 1 then
+ if nargs == 0 then
+ if g_opt.dumpdef > 0 then return dumpdef(stdout) end
+ end
+ opt_map.help()
+ end
+
+ -- Translate a single input file to a single output file
+ -- TODO: Handle multiple files?
+ translate(args[args.argn], g_opt.outfile)
+end
+
+------------------------------------------------------------------------------
+
+-- Add the directory dynasm.lua resides in to the Lua module search path.
+local arg = arg
+if arg and arg[0] then
+ prefix = match(arg[0], "^(.*[/\\])")
+ if package and prefix then package.path = prefix.."?.lua;"..package.path end
+end
+
+-- Start DynASM.
+parseargs{...}
+
+------------------------------------------------------------------------------
+
diff --git a/ext/opcache/jit/dynasm/minilua.c b/ext/opcache/jit/dynasm/minilua.c
new file mode 100644
index 0000000000..a8d7c305e1
--- /dev/null
+++ b/ext/opcache/jit/dynasm/minilua.c
@@ -0,0 +1,7770 @@
+/* This is a heavily customized and minimized copy of Lua 5.1.5. */
+/* It's only used to build LuaJIT. It does NOT have all standard functions! */
+/******************************************************************************
+* Copyright (C) 1994-2012 Lua.org, PUC-Rio. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to deal in the Software without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
+#ifdef _MSC_VER
+typedef unsigned __int64 U64;
+#else
+typedef unsigned long long U64;
+#endif
+int _CRT_glob = 0;
+#include <stddef.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <math.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <time.h>
+typedef enum{
+TM_INDEX,
+TM_NEWINDEX,
+TM_GC,
+TM_MODE,
+TM_EQ,
+TM_ADD,
+TM_SUB,
+TM_MUL,
+TM_DIV,
+TM_MOD,
+TM_POW,
+TM_UNM,
+TM_LEN,
+TM_LT,
+TM_LE,
+TM_CONCAT,
+TM_CALL,
+TM_N
+}TMS;
+enum OpMode{iABC,iABx,iAsBx};
+typedef enum{
+OP_MOVE,
+OP_LOADK,
+OP_LOADBOOL,
+OP_LOADNIL,
+OP_GETUPVAL,
+OP_GETGLOBAL,
+OP_GETTABLE,
+OP_SETGLOBAL,
+OP_SETUPVAL,
+OP_SETTABLE,
+OP_NEWTABLE,
+OP_SELF,
+OP_ADD,
+OP_SUB,
+OP_MUL,
+OP_DIV,
+OP_MOD,
+OP_POW,
+OP_UNM,
+OP_NOT,
+OP_LEN,
+OP_CONCAT,
+OP_JMP,
+OP_EQ,
+OP_LT,
+OP_LE,
+OP_TEST,
+OP_TESTSET,
+OP_CALL,
+OP_TAILCALL,
+OP_RETURN,
+OP_FORLOOP,
+OP_FORPREP,
+OP_TFORLOOP,
+OP_SETLIST,
+OP_CLOSE,
+OP_CLOSURE,
+OP_VARARG
+}OpCode;
+enum OpArgMask{
+OpArgN,
+OpArgU,
+OpArgR,
+OpArgK
+};
+typedef enum{
+VVOID,
+VNIL,
+VTRUE,
+VFALSE,
+VK,
+VKNUM,
+VLOCAL,
+VUPVAL,
+VGLOBAL,
+VINDEXED,
+VJMP,
+VRELOCABLE,
+VNONRELOC,
+VCALL,
+VVARARG
+}expkind;
+enum RESERVED{
+TK_AND=257,TK_BREAK,
+TK_DO,TK_ELSE,TK_ELSEIF,TK_END,TK_FALSE,TK_FOR,TK_FUNCTION,
+TK_IF,TK_IN,TK_LOCAL,TK_NIL,TK_NOT,TK_OR,TK_REPEAT,
+TK_RETURN,TK_THEN,TK_TRUE,TK_UNTIL,TK_WHILE,
+TK_CONCAT,TK_DOTS,TK_EQ,TK_GE,TK_LE,TK_NE,TK_NUMBER,
+TK_NAME,TK_STRING,TK_EOS
+};
+typedef enum BinOpr{
+OPR_ADD,OPR_SUB,OPR_MUL,OPR_DIV,OPR_MOD,OPR_POW,
+OPR_CONCAT,
+OPR_NE,OPR_EQ,
+OPR_LT,OPR_LE,OPR_GT,OPR_GE,
+OPR_AND,OPR_OR,
+OPR_NOBINOPR
+}BinOpr;
+typedef enum UnOpr{OPR_MINUS,OPR_NOT,OPR_LEN,OPR_NOUNOPR}UnOpr;
+#define LUA_QL(x)"'"x"'"
+#define luai_apicheck(L,o){(void)L;}
+#define lua_number2str(s,n)sprintf((s),"%.14g",(n))
+#define lua_str2number(s,p)strtod((s),(p))
+#define luai_numadd(a,b)((a)+(b))
+#define luai_numsub(a,b)((a)-(b))
+#define luai_nummul(a,b)((a)*(b))
+#define luai_numdiv(a,b)((a)/(b))
+#define luai_nummod(a,b)((a)-floor((a)/(b))*(b))
+#define luai_numpow(a,b)(pow(a,b))
+#define luai_numunm(a)(-(a))
+#define luai_numeq(a,b)((a)==(b))
+#define luai_numlt(a,b)((a)<(b))
+#define luai_numle(a,b)((a)<=(b))
+#define luai_numisnan(a)(!luai_numeq((a),(a)))
+#define lua_number2int(i,d)((i)=(int)(d))
+#define lua_number2integer(i,d)((i)=(lua_Integer)(d))
+#define LUAI_THROW(L,c)longjmp((c)->b,1)
+#define LUAI_TRY(L,c,a)if(setjmp((c)->b)==0){a}
+#define lua_pclose(L,file)((void)((void)L,file),0)
+#define lua_upvalueindex(i)((-10002)-(i))
+typedef struct lua_State lua_State;
+typedef int(*lua_CFunction)(lua_State*L);
+typedef const char*(*lua_Reader)(lua_State*L,void*ud,size_t*sz);
+typedef void*(*lua_Alloc)(void*ud,void*ptr,size_t osize,size_t nsize);
+typedef double lua_Number;
+typedef ptrdiff_t lua_Integer;
+static void lua_settop(lua_State*L,int idx);
+static int lua_type(lua_State*L,int idx);
+static const char* lua_tolstring(lua_State*L,int idx,size_t*len);
+static size_t lua_objlen(lua_State*L,int idx);
+static void lua_pushlstring(lua_State*L,const char*s,size_t l);
+static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n);
+static void lua_createtable(lua_State*L,int narr,int nrec);
+static void lua_setfield(lua_State*L,int idx,const char*k);
+#define lua_pop(L,n)lua_settop(L,-(n)-1)
+#define lua_newtable(L)lua_createtable(L,0,0)
+#define lua_pushcfunction(L,f)lua_pushcclosure(L,(f),0)
+#define lua_strlen(L,i)lua_objlen(L,(i))
+#define lua_isfunction(L,n)(lua_type(L,(n))==6)
+#define lua_istable(L,n)(lua_type(L,(n))==5)
+#define lua_isnil(L,n)(lua_type(L,(n))==0)
+#define lua_isboolean(L,n)(lua_type(L,(n))==1)
+#define lua_isnone(L,n)(lua_type(L,(n))==(-1))
+#define lua_isnoneornil(L,n)(lua_type(L,(n))<=0)
+#define lua_pushliteral(L,s)lua_pushlstring(L,""s,(sizeof(s)/sizeof(char))-1)
+#define lua_setglobal(L,s)lua_setfield(L,(-10002),(s))
+#define lua_tostring(L,i)lua_tolstring(L,(i),NULL)
+typedef struct lua_Debug lua_Debug;
+typedef void(*lua_Hook)(lua_State*L,lua_Debug*ar);
+struct lua_Debug{
+int event;
+const char*name;
+const char*namewhat;
+const char*what;
+const char*source;
+int currentline;
+int nups;
+int linedefined;
+int lastlinedefined;
+char short_src[60];
+int i_ci;
+};
+typedef unsigned int lu_int32;
+typedef size_t lu_mem;
+typedef ptrdiff_t l_mem;
+typedef unsigned char lu_byte;
+#define IntPoint(p)((unsigned int)(lu_mem)(p))
+typedef union{double u;void*s;long l;}L_Umaxalign;
+typedef double l_uacNumber;
+#define check_exp(c,e)(e)
+#define UNUSED(x)((void)(x))
+#define cast(t,exp)((t)(exp))
+#define cast_byte(i)cast(lu_byte,(i))
+#define cast_num(i)cast(lua_Number,(i))
+#define cast_int(i)cast(int,(i))
+typedef lu_int32 Instruction;
+#define condhardstacktests(x)((void)0)
+typedef union GCObject GCObject;
+typedef struct GCheader{
+GCObject*next;lu_byte tt;lu_byte marked;
+}GCheader;
+typedef union{
+GCObject*gc;
+void*p;
+lua_Number n;
+int b;
+}Value;
+typedef struct lua_TValue{
+Value value;int tt;
+}TValue;
+#define ttisnil(o)(ttype(o)==0)
+#define ttisnumber(o)(ttype(o)==3)
+#define ttisstring(o)(ttype(o)==4)
+#define ttistable(o)(ttype(o)==5)
+#define ttisfunction(o)(ttype(o)==6)
+#define ttisboolean(o)(ttype(o)==1)
+#define ttisuserdata(o)(ttype(o)==7)
+#define ttisthread(o)(ttype(o)==8)
+#define ttislightuserdata(o)(ttype(o)==2)
+#define ttype(o)((o)->tt)
+#define gcvalue(o)check_exp(iscollectable(o),(o)->value.gc)
+#define pvalue(o)check_exp(ttislightuserdata(o),(o)->value.p)
+#define nvalue(o)check_exp(ttisnumber(o),(o)->value.n)
+#define rawtsvalue(o)check_exp(ttisstring(o),&(o)->value.gc->ts)
+#define tsvalue(o)(&rawtsvalue(o)->tsv)
+#define rawuvalue(o)check_exp(ttisuserdata(o),&(o)->value.gc->u)
+#define uvalue(o)(&rawuvalue(o)->uv)
+#define clvalue(o)check_exp(ttisfunction(o),&(o)->value.gc->cl)
+#define hvalue(o)check_exp(ttistable(o),&(o)->value.gc->h)
+#define bvalue(o)check_exp(ttisboolean(o),(o)->value.b)
+#define thvalue(o)check_exp(ttisthread(o),&(o)->value.gc->th)
+#define l_isfalse(o)(ttisnil(o)||(ttisboolean(o)&&bvalue(o)==0))
+#define checkconsistency(obj)
+#define checkliveness(g,obj)
+#define setnilvalue(obj)((obj)->tt=0)
+#define setnvalue(obj,x){TValue*i_o=(obj);i_o->value.n=(x);i_o->tt=3;}
+#define setbvalue(obj,x){TValue*i_o=(obj);i_o->value.b=(x);i_o->tt=1;}
+#define setsvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=4;checkliveness(G(L),i_o);}
+#define setuvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=7;checkliveness(G(L),i_o);}
+#define setthvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=8;checkliveness(G(L),i_o);}
+#define setclvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=6;checkliveness(G(L),i_o);}
+#define sethvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=5;checkliveness(G(L),i_o);}
+#define setptvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=(8+1);checkliveness(G(L),i_o);}
+#define setobj(L,obj1,obj2){const TValue*o2=(obj2);TValue*o1=(obj1);o1->value=o2->value;o1->tt=o2->tt;checkliveness(G(L),o1);}
+#define setttype(obj,tt)(ttype(obj)=(tt))
+#define iscollectable(o)(ttype(o)>=4)
+typedef TValue*StkId;
+typedef union TString{
+L_Umaxalign dummy;
+struct{
+GCObject*next;lu_byte tt;lu_byte marked;
+lu_byte reserved;
+unsigned int hash;
+size_t len;
+}tsv;
+}TString;
+#define getstr(ts)cast(const char*,(ts)+1)
+#define svalue(o)getstr(rawtsvalue(o))
+typedef union Udata{
+L_Umaxalign dummy;
+struct{
+GCObject*next;lu_byte tt;lu_byte marked;
+struct Table*metatable;
+struct Table*env;
+size_t len;
+}uv;
+}Udata;
+typedef struct Proto{
+GCObject*next;lu_byte tt;lu_byte marked;
+TValue*k;
+Instruction*code;
+struct Proto**p;
+int*lineinfo;
+struct LocVar*locvars;
+TString**upvalues;
+TString*source;
+int sizeupvalues;
+int sizek;
+int sizecode;
+int sizelineinfo;
+int sizep;
+int sizelocvars;
+int linedefined;
+int lastlinedefined;
+GCObject*gclist;
+lu_byte nups;
+lu_byte numparams;
+lu_byte is_vararg;
+lu_byte maxstacksize;
+}Proto;
+typedef struct LocVar{
+TString*varname;
+int startpc;
+int endpc;
+}LocVar;
+typedef struct UpVal{
+GCObject*next;lu_byte tt;lu_byte marked;
+TValue*v;
+union{
+TValue value;
+struct{
+struct UpVal*prev;
+struct UpVal*next;
+}l;
+}u;
+}UpVal;
+typedef struct CClosure{
+GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env;
+lua_CFunction f;
+TValue upvalue[1];
+}CClosure;
+typedef struct LClosure{
+GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env;
+struct Proto*p;
+UpVal*upvals[1];
+}LClosure;
+typedef union Closure{
+CClosure c;
+LClosure l;
+}Closure;
+#define iscfunction(o)(ttype(o)==6&&clvalue(o)->c.isC)
+typedef union TKey{
+struct{
+Value value;int tt;
+struct Node*next;
+}nk;
+TValue tvk;
+}TKey;
+typedef struct Node{
+TValue i_val;
+TKey i_key;
+}Node;
+typedef struct Table{
+GCObject*next;lu_byte tt;lu_byte marked;
+lu_byte flags;
+lu_byte lsizenode;
+struct Table*metatable;
+TValue*array;
+Node*node;
+Node*lastfree;
+GCObject*gclist;
+int sizearray;
+}Table;
+#define lmod(s,size)(check_exp((size&(size-1))==0,(cast(int,(s)&((size)-1)))))
+#define twoto(x)((size_t)1<<(x))
+#define sizenode(t)(twoto((t)->lsizenode))
+static const TValue luaO_nilobject_;
+#define ceillog2(x)(luaO_log2((x)-1)+1)
+static int luaO_log2(unsigned int x);
+#define gfasttm(g,et,e)((et)==NULL?NULL:((et)->flags&(1u<<(e)))?NULL:luaT_gettm(et,e,(g)->tmname[e]))
+#define fasttm(l,et,e)gfasttm(G(l),et,e)
+static const TValue*luaT_gettm(Table*events,TMS event,TString*ename);
+#define luaM_reallocv(L,b,on,n,e)((cast(size_t,(n)+1)<=((size_t)(~(size_t)0)-2)/(e))?luaM_realloc_(L,(b),(on)*(e),(n)*(e)):luaM_toobig(L))
+#define luaM_freemem(L,b,s)luaM_realloc_(L,(b),(s),0)
+#define luaM_free(L,b)luaM_realloc_(L,(b),sizeof(*(b)),0)
+#define luaM_freearray(L,b,n,t)luaM_reallocv(L,(b),n,0,sizeof(t))
+#define luaM_malloc(L,t)luaM_realloc_(L,NULL,0,(t))
+#define luaM_new(L,t)cast(t*,luaM_malloc(L,sizeof(t)))
+#define luaM_newvector(L,n,t)cast(t*,luaM_reallocv(L,NULL,0,n,sizeof(t)))
+#define luaM_growvector(L,v,nelems,size,t,limit,e)if((nelems)+1>(size))((v)=cast(t*,luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
+#define luaM_reallocvector(L,v,oldn,n,t)((v)=cast(t*,luaM_reallocv(L,v,oldn,n,sizeof(t))))
+static void*luaM_realloc_(lua_State*L,void*block,size_t oldsize,
+size_t size);
+static void*luaM_toobig(lua_State*L);
+static void*luaM_growaux_(lua_State*L,void*block,int*size,
+size_t size_elem,int limit,
+const char*errormsg);
+typedef struct Zio ZIO;
+#define char2int(c)cast(int,cast(unsigned char,(c)))
+#define zgetc(z)(((z)->n--)>0?char2int(*(z)->p++):luaZ_fill(z))
+typedef struct Mbuffer{
+char*buffer;
+size_t n;
+size_t buffsize;
+}Mbuffer;
+#define luaZ_initbuffer(L,buff)((buff)->buffer=NULL,(buff)->buffsize=0)
+#define luaZ_buffer(buff)((buff)->buffer)
+#define luaZ_sizebuffer(buff)((buff)->buffsize)
+#define luaZ_bufflen(buff)((buff)->n)
+#define luaZ_resetbuffer(buff)((buff)->n=0)
+#define luaZ_resizebuffer(L,buff,size)(luaM_reallocvector(L,(buff)->buffer,(buff)->buffsize,size,char),(buff)->buffsize=size)
+#define luaZ_freebuffer(L,buff)luaZ_resizebuffer(L,buff,0)
+struct Zio{
+size_t n;
+const char*p;
+lua_Reader reader;
+void*data;
+lua_State*L;
+};
+static int luaZ_fill(ZIO*z);
+struct lua_longjmp;
+#define gt(L)(&L->l_gt)
+#define registry(L)(&G(L)->l_registry)
+typedef struct stringtable{
+GCObject**hash;
+lu_int32 nuse;
+int size;
+}stringtable;
+typedef struct CallInfo{
+StkId base;
+StkId func;
+StkId top;
+const Instruction*savedpc;
+int nresults;
+int tailcalls;
+}CallInfo;
+#define curr_func(L)(clvalue(L->ci->func))
+#define ci_func(ci)(clvalue((ci)->func))
+#define f_isLua(ci)(!ci_func(ci)->c.isC)
+#define isLua(ci)(ttisfunction((ci)->func)&&f_isLua(ci))
+typedef struct global_State{
+stringtable strt;
+lua_Alloc frealloc;
+void*ud;
+lu_byte currentwhite;
+lu_byte gcstate;
+int sweepstrgc;
+GCObject*rootgc;
+GCObject**sweepgc;
+GCObject*gray;
+GCObject*grayagain;
+GCObject*weak;
+GCObject*tmudata;
+Mbuffer buff;
+lu_mem GCthreshold;
+lu_mem totalbytes;
+lu_mem estimate;
+lu_mem gcdept;
+int gcpause;
+int gcstepmul;
+lua_CFunction panic;
+TValue l_registry;
+struct lua_State*mainthread;
+UpVal uvhead;
+struct Table*mt[(8+1)];
+TString*tmname[TM_N];
+}global_State;
+struct lua_State{
+GCObject*next;lu_byte tt;lu_byte marked;
+lu_byte status;
+StkId top;
+StkId base;
+global_State*l_G;
+CallInfo*ci;
+const Instruction*savedpc;
+StkId stack_last;
+StkId stack;
+CallInfo*end_ci;
+CallInfo*base_ci;
+int stacksize;
+int size_ci;
+unsigned short nCcalls;
+unsigned short baseCcalls;
+lu_byte hookmask;
+lu_byte allowhook;
+int basehookcount;
+int hookcount;
+lua_Hook hook;
+TValue l_gt;
+TValue env;
+GCObject*openupval;
+GCObject*gclist;
+struct lua_longjmp*errorJmp;
+ptrdiff_t errfunc;
+};
+#define G(L)(L->l_G)
+union GCObject{
+GCheader gch;
+union TString ts;
+union Udata u;
+union Closure cl;
+struct Table h;
+struct Proto p;
+struct UpVal uv;
+struct lua_State th;
+};
+#define rawgco2ts(o)check_exp((o)->gch.tt==4,&((o)->ts))
+#define gco2ts(o)(&rawgco2ts(o)->tsv)
+#define rawgco2u(o)check_exp((o)->gch.tt==7,&((o)->u))
+#define gco2u(o)(&rawgco2u(o)->uv)
+#define gco2cl(o)check_exp((o)->gch.tt==6,&((o)->cl))
+#define gco2h(o)check_exp((o)->gch.tt==5,&((o)->h))
+#define gco2p(o)check_exp((o)->gch.tt==(8+1),&((o)->p))
+#define gco2uv(o)check_exp((o)->gch.tt==(8+2),&((o)->uv))
+#define ngcotouv(o)check_exp((o)==NULL||(o)->gch.tt==(8+2),&((o)->uv))
+#define gco2th(o)check_exp((o)->gch.tt==8,&((o)->th))
+#define obj2gco(v)(cast(GCObject*,(v)))
+static void luaE_freethread(lua_State*L,lua_State*L1);
+#define pcRel(pc,p)(cast(int,(pc)-(p)->code)-1)
+#define getline_(f,pc)(((f)->lineinfo)?(f)->lineinfo[pc]:0)
+#define resethookcount(L)(L->hookcount=L->basehookcount)
+static void luaG_typeerror(lua_State*L,const TValue*o,
+const char*opname);
+static void luaG_runerror(lua_State*L,const char*fmt,...);
+#define luaD_checkstack(L,n)if((char*)L->stack_last-(char*)L->top<=(n)*(int)sizeof(TValue))luaD_growstack(L,n);else condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1));
+#define incr_top(L){luaD_checkstack(L,1);L->top++;}
+#define savestack(L,p)((char*)(p)-(char*)L->stack)
+#define restorestack(L,n)((TValue*)((char*)L->stack+(n)))
+#define saveci(L,p)((char*)(p)-(char*)L->base_ci)
+#define restoreci(L,n)((CallInfo*)((char*)L->base_ci+(n)))
+typedef void(*Pfunc)(lua_State*L,void*ud);
+static int luaD_poscall(lua_State*L,StkId firstResult);
+static void luaD_reallocCI(lua_State*L,int newsize);
+static void luaD_reallocstack(lua_State*L,int newsize);
+static void luaD_growstack(lua_State*L,int n);
+static void luaD_throw(lua_State*L,int errcode);
+static void*luaM_growaux_(lua_State*L,void*block,int*size,size_t size_elems,
+int limit,const char*errormsg){
+void*newblock;
+int newsize;
+if(*size>=limit/2){
+if(*size>=limit)
+luaG_runerror(L,errormsg);
+newsize=limit;
+}
+else{
+newsize=(*size)*2;
+if(newsize<4)
+newsize=4;
+}
+newblock=luaM_reallocv(L,block,*size,newsize,size_elems);
+*size=newsize;
+return newblock;
+}
+static void*luaM_toobig(lua_State*L){
+luaG_runerror(L,"memory allocation error: block too big");
+return NULL;
+}
+static void*luaM_realloc_(lua_State*L,void*block,size_t osize,size_t nsize){
+global_State*g=G(L);
+block=(*g->frealloc)(g->ud,block,osize,nsize);
+if(block==NULL&&nsize>0)
+luaD_throw(L,4);
+g->totalbytes=(g->totalbytes-osize)+nsize;
+return block;
+}
+#define resetbits(x,m)((x)&=cast(lu_byte,~(m)))
+#define setbits(x,m)((x)|=(m))
+#define testbits(x,m)((x)&(m))
+#define bitmask(b)(1<<(b))
+#define bit2mask(b1,b2)(bitmask(b1)|bitmask(b2))
+#define l_setbit(x,b)setbits(x,bitmask(b))
+#define resetbit(x,b)resetbits(x,bitmask(b))
+#define testbit(x,b)testbits(x,bitmask(b))
+#define set2bits(x,b1,b2)setbits(x,(bit2mask(b1,b2)))
+#define reset2bits(x,b1,b2)resetbits(x,(bit2mask(b1,b2)))
+#define test2bits(x,b1,b2)testbits(x,(bit2mask(b1,b2)))
+#define iswhite(x)test2bits((x)->gch.marked,0,1)
+#define isblack(x)testbit((x)->gch.marked,2)
+#define isgray(x)(!isblack(x)&&!iswhite(x))
+#define otherwhite(g)(g->currentwhite^bit2mask(0,1))
+#define isdead(g,v)((v)->gch.marked&otherwhite(g)&bit2mask(0,1))
+#define changewhite(x)((x)->gch.marked^=bit2mask(0,1))
+#define gray2black(x)l_setbit((x)->gch.marked,2)
+#define valiswhite(x)(iscollectable(x)&&iswhite(gcvalue(x)))
+#define luaC_white(g)cast(lu_byte,(g)->currentwhite&bit2mask(0,1))
+#define luaC_checkGC(L){condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1));if(G(L)->totalbytes>=G(L)->GCthreshold)luaC_step(L);}
+#define luaC_barrier(L,p,v){if(valiswhite(v)&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),gcvalue(v));}
+#define luaC_barriert(L,t,v){if(valiswhite(v)&&isblack(obj2gco(t)))luaC_barrierback(L,t);}
+#define luaC_objbarrier(L,p,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),obj2gco(o));}
+#define luaC_objbarriert(L,t,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(t)))luaC_barrierback(L,t);}
+static void luaC_step(lua_State*L);
+static void luaC_link(lua_State*L,GCObject*o,lu_byte tt);
+static void luaC_linkupval(lua_State*L,UpVal*uv);
+static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v);
+static void luaC_barrierback(lua_State*L,Table*t);
+#define sizestring(s)(sizeof(union TString)+((s)->len+1)*sizeof(char))
+#define sizeudata(u)(sizeof(union Udata)+(u)->len)
+#define luaS_new(L,s)(luaS_newlstr(L,s,strlen(s)))
+#define luaS_newliteral(L,s)(luaS_newlstr(L,""s,(sizeof(s)/sizeof(char))-1))
+#define luaS_fix(s)l_setbit((s)->tsv.marked,5)
+static TString*luaS_newlstr(lua_State*L,const char*str,size_t l);
+#define tostring(L,o)((ttype(o)==4)||(luaV_tostring(L,o)))
+#define tonumber(o,n)(ttype(o)==3||(((o)=luaV_tonumber(o,n))!=NULL))
+#define equalobj(L,o1,o2)(ttype(o1)==ttype(o2)&&luaV_equalval(L,o1,o2))
+static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2);
+static const TValue*luaV_tonumber(const TValue*obj,TValue*n);
+static int luaV_tostring(lua_State*L,StkId obj);
+static void luaV_execute(lua_State*L,int nexeccalls);
+static void luaV_concat(lua_State*L,int total,int last);
+static const TValue luaO_nilobject_={{NULL},0};
+static int luaO_int2fb(unsigned int x){
+int e=0;
+while(x>=16){
+x=(x+1)>>1;
+e++;
+}
+if(x<8)return x;
+else return((e+1)<<3)|(cast_int(x)-8);
+}
+static int luaO_fb2int(int x){
+int e=(x>>3)&31;
+if(e==0)return x;
+else return((x&7)+8)<<(e-1);
+}
+static int luaO_log2(unsigned int x){
+static const lu_byte log_2[256]={
+0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+};
+int l=-1;
+while(x>=256){l+=8;x>>=8;}
+return l+log_2[x];
+}
+static int luaO_rawequalObj(const TValue*t1,const TValue*t2){
+if(ttype(t1)!=ttype(t2))return 0;
+else switch(ttype(t1)){
+case 0:
+return 1;
+case 3:
+return luai_numeq(nvalue(t1),nvalue(t2));
+case 1:
+return bvalue(t1)==bvalue(t2);
+case 2:
+return pvalue(t1)==pvalue(t2);
+default:
+return gcvalue(t1)==gcvalue(t2);
+}
+}
+static int luaO_str2d(const char*s,lua_Number*result){
+char*endptr;
+*result=lua_str2number(s,&endptr);
+if(endptr==s)return 0;
+if(*endptr=='x'||*endptr=='X')
+*result=cast_num(strtoul(s,&endptr,16));
+if(*endptr=='\0')return 1;
+while(isspace(cast(unsigned char,*endptr)))endptr++;
+if(*endptr!='\0')return 0;
+return 1;
+}
+static void pushstr(lua_State*L,const char*str){
+setsvalue(L,L->top,luaS_new(L,str));
+incr_top(L);
+}
+static const char*luaO_pushvfstring(lua_State*L,const char*fmt,va_list argp){
+int n=1;
+pushstr(L,"");
+for(;;){
+const char*e=strchr(fmt,'%');
+if(e==NULL)break;
+setsvalue(L,L->top,luaS_newlstr(L,fmt,e-fmt));
+incr_top(L);
+switch(*(e+1)){
+case's':{
+const char*s=va_arg(argp,char*);
+if(s==NULL)s="(null)";
+pushstr(L,s);
+break;
+}
+case'c':{
+char buff[2];
+buff[0]=cast(char,va_arg(argp,int));
+buff[1]='\0';
+pushstr(L,buff);
+break;
+}
+case'd':{
+setnvalue(L->top,cast_num(va_arg(argp,int)));
+incr_top(L);
+break;
+}
+case'f':{
+setnvalue(L->top,cast_num(va_arg(argp,l_uacNumber)));
+incr_top(L);
+break;
+}
+case'p':{
+char buff[4*sizeof(void*)+8];
+sprintf(buff,"%p",va_arg(argp,void*));
+pushstr(L,buff);
+break;
+}
+case'%':{
+pushstr(L,"%");
+break;
+}
+default:{
+char buff[3];
+buff[0]='%';
+buff[1]=*(e+1);
+buff[2]='\0';
+pushstr(L,buff);
+break;
+}
+}
+n+=2;
+fmt=e+2;
+}
+pushstr(L,fmt);
+luaV_concat(L,n+1,cast_int(L->top-L->base)-1);
+L->top-=n;
+return svalue(L->top-1);
+}
+static const char*luaO_pushfstring(lua_State*L,const char*fmt,...){
+const char*msg;
+va_list argp;
+va_start(argp,fmt);
+msg=luaO_pushvfstring(L,fmt,argp);
+va_end(argp);
+return msg;
+}
+static void luaO_chunkid(char*out,const char*source,size_t bufflen){
+if(*source=='='){
+strncpy(out,source+1,bufflen);
+out[bufflen-1]='\0';
+}
+else{
+if(*source=='@'){
+size_t l;
+source++;
+bufflen-=sizeof(" '...' ");
+l=strlen(source);
+strcpy(out,"");
+if(l>bufflen){
+source+=(l-bufflen);
+strcat(out,"...");
+}
+strcat(out,source);
+}
+else{
+size_t len=strcspn(source,"\n\r");
+bufflen-=sizeof(" [string \"...\"] ");
+if(len>bufflen)len=bufflen;
+strcpy(out,"[string \"");
+if(source[len]!='\0'){
+strncat(out,source,len);
+strcat(out,"...");
+}
+else
+strcat(out,source);
+strcat(out,"\"]");
+}
+}
+}
+#define gnode(t,i)(&(t)->node[i])
+#define gkey(n)(&(n)->i_key.nk)
+#define gval(n)(&(n)->i_val)
+#define gnext(n)((n)->i_key.nk.next)
+#define key2tval(n)(&(n)->i_key.tvk)
+static TValue*luaH_setnum(lua_State*L,Table*t,int key);
+static const TValue*luaH_getstr(Table*t,TString*key);
+static TValue*luaH_set(lua_State*L,Table*t,const TValue*key);
+static const char*const luaT_typenames[]={
+"nil","boolean","userdata","number",
+"string","table","function","userdata","thread",
+"proto","upval"
+};
+static void luaT_init(lua_State*L){
+static const char*const luaT_eventname[]={
+"__index","__newindex",
+"__gc","__mode","__eq",
+"__add","__sub","__mul","__div","__mod",
+"__pow","__unm","__len","__lt","__le",
+"__concat","__call"
+};
+int i;
+for(i=0;i<TM_N;i++){
+G(L)->tmname[i]=luaS_new(L,luaT_eventname[i]);
+luaS_fix(G(L)->tmname[i]);
+}
+}
+static const TValue*luaT_gettm(Table*events,TMS event,TString*ename){
+const TValue*tm=luaH_getstr(events,ename);
+if(ttisnil(tm)){
+events->flags|=cast_byte(1u<<event);
+return NULL;
+}
+else return tm;
+}
+static const TValue*luaT_gettmbyobj(lua_State*L,const TValue*o,TMS event){
+Table*mt;
+switch(ttype(o)){
+case 5:
+mt=hvalue(o)->metatable;
+break;
+case 7:
+mt=uvalue(o)->metatable;
+break;
+default:
+mt=G(L)->mt[ttype(o)];
+}
+return(mt?luaH_getstr(mt,G(L)->tmname[event]):(&luaO_nilobject_));
+}
+#define sizeCclosure(n)(cast(int,sizeof(CClosure))+cast(int,sizeof(TValue)*((n)-1)))
+#define sizeLclosure(n)(cast(int,sizeof(LClosure))+cast(int,sizeof(TValue*)*((n)-1)))
+static Closure*luaF_newCclosure(lua_State*L,int nelems,Table*e){
+Closure*c=cast(Closure*,luaM_malloc(L,sizeCclosure(nelems)));
+luaC_link(L,obj2gco(c),6);
+c->c.isC=1;
+c->c.env=e;
+c->c.nupvalues=cast_byte(nelems);
+return c;
+}
+static Closure*luaF_newLclosure(lua_State*L,int nelems,Table*e){
+Closure*c=cast(Closure*,luaM_malloc(L,sizeLclosure(nelems)));
+luaC_link(L,obj2gco(c),6);
+c->l.isC=0;
+c->l.env=e;
+c->l.nupvalues=cast_byte(nelems);
+while(nelems--)c->l.upvals[nelems]=NULL;
+return c;
+}
+static UpVal*luaF_newupval(lua_State*L){
+UpVal*uv=luaM_new(L,UpVal);
+luaC_link(L,obj2gco(uv),(8+2));
+uv->v=&uv->u.value;
+setnilvalue(uv->v);
+return uv;
+}
+static UpVal*luaF_findupval(lua_State*L,StkId level){
+global_State*g=G(L);
+GCObject**pp=&L->openupval;
+UpVal*p;
+UpVal*uv;
+while(*pp!=NULL&&(p=ngcotouv(*pp))->v>=level){
+if(p->v==level){
+if(isdead(g,obj2gco(p)))
+changewhite(obj2gco(p));
+return p;
+}
+pp=&p->next;
+}
+uv=luaM_new(L,UpVal);
+uv->tt=(8+2);
+uv->marked=luaC_white(g);
+uv->v=level;
+uv->next=*pp;
+*pp=obj2gco(uv);
+uv->u.l.prev=&g->uvhead;
+uv->u.l.next=g->uvhead.u.l.next;
+uv->u.l.next->u.l.prev=uv;
+g->uvhead.u.l.next=uv;
+return uv;
+}
+static void unlinkupval(UpVal*uv){
+uv->u.l.next->u.l.prev=uv->u.l.prev;
+uv->u.l.prev->u.l.next=uv->u.l.next;
+}
+static void luaF_freeupval(lua_State*L,UpVal*uv){
+if(uv->v!=&uv->u.value)
+unlinkupval(uv);
+luaM_free(L,uv);
+}
+static void luaF_close(lua_State*L,StkId level){
+UpVal*uv;
+global_State*g=G(L);
+while(L->openupval!=NULL&&(uv=ngcotouv(L->openupval))->v>=level){
+GCObject*o=obj2gco(uv);
+L->openupval=uv->next;
+if(isdead(g,o))
+luaF_freeupval(L,uv);
+else{
+unlinkupval(uv);
+setobj(L,&uv->u.value,uv->v);
+uv->v=&uv->u.value;
+luaC_linkupval(L,uv);
+}
+}
+}
+static Proto*luaF_newproto(lua_State*L){
+Proto*f=luaM_new(L,Proto);
+luaC_link(L,obj2gco(f),(8+1));
+f->k=NULL;
+f->sizek=0;
+f->p=NULL;
+f->sizep=0;
+f->code=NULL;
+f->sizecode=0;
+f->sizelineinfo=0;
+f->sizeupvalues=0;
+f->nups=0;
+f->upvalues=NULL;
+f->numparams=0;
+f->is_vararg=0;
+f->maxstacksize=0;
+f->lineinfo=NULL;
+f->sizelocvars=0;
+f->locvars=NULL;
+f->linedefined=0;
+f->lastlinedefined=0;
+f->source=NULL;
+return f;
+}
+static void luaF_freeproto(lua_State*L,Proto*f){
+luaM_freearray(L,f->code,f->sizecode,Instruction);
+luaM_freearray(L,f->p,f->sizep,Proto*);
+luaM_freearray(L,f->k,f->sizek,TValue);
+luaM_freearray(L,f->lineinfo,f->sizelineinfo,int);
+luaM_freearray(L,f->locvars,f->sizelocvars,struct LocVar);
+luaM_freearray(L,f->upvalues,f->sizeupvalues,TString*);
+luaM_free(L,f);
+}
+static void luaF_freeclosure(lua_State*L,Closure*c){
+int size=(c->c.isC)?sizeCclosure(c->c.nupvalues):
+sizeLclosure(c->l.nupvalues);
+luaM_freemem(L,c,size);
+}
+#define MASK1(n,p)((~((~(Instruction)0)<<n))<<p)
+#define MASK0(n,p)(~MASK1(n,p))
+#define GET_OPCODE(i)(cast(OpCode,((i)>>0)&MASK1(6,0)))
+#define SET_OPCODE(i,o)((i)=(((i)&MASK0(6,0))|((cast(Instruction,o)<<0)&MASK1(6,0))))
+#define GETARG_A(i)(cast(int,((i)>>(0+6))&MASK1(8,0)))
+#define SETARG_A(i,u)((i)=(((i)&MASK0(8,(0+6)))|((cast(Instruction,u)<<(0+6))&MASK1(8,(0+6)))))
+#define GETARG_B(i)(cast(int,((i)>>(((0+6)+8)+9))&MASK1(9,0)))
+#define SETARG_B(i,b)((i)=(((i)&MASK0(9,(((0+6)+8)+9)))|((cast(Instruction,b)<<(((0+6)+8)+9))&MASK1(9,(((0+6)+8)+9)))))
+#define GETARG_C(i)(cast(int,((i)>>((0+6)+8))&MASK1(9,0)))
+#define SETARG_C(i,b)((i)=(((i)&MASK0(9,((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1(9,((0+6)+8)))))
+#define GETARG_Bx(i)(cast(int,((i)>>((0+6)+8))&MASK1((9+9),0)))
+#define SETARG_Bx(i,b)((i)=(((i)&MASK0((9+9),((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1((9+9),((0+6)+8)))))
+#define GETARG_sBx(i)(GETARG_Bx(i)-(((1<<(9+9))-1)>>1))
+#define SETARG_sBx(i,b)SETARG_Bx((i),cast(unsigned int,(b)+(((1<<(9+9))-1)>>1)))
+#define CREATE_ABC(o,a,b,c)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,b)<<(((0+6)+8)+9))|(cast(Instruction,c)<<((0+6)+8)))
+#define CREATE_ABx(o,a,bc)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,bc)<<((0+6)+8)))
+#define ISK(x)((x)&(1<<(9-1)))
+#define INDEXK(r)((int)(r)&~(1<<(9-1)))
+#define RKASK(x)((x)|(1<<(9-1)))
+static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)];
+#define getBMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>4)&3))
+#define getCMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>2)&3))
+#define testTMode(m)(luaP_opmodes[m]&(1<<7))
+typedef struct expdesc{
+expkind k;
+union{
+struct{int info,aux;}s;
+lua_Number nval;
+}u;
+int t;
+int f;
+}expdesc;
+typedef struct upvaldesc{
+lu_byte k;
+lu_byte info;
+}upvaldesc;
+struct BlockCnt;
+typedef struct FuncState{
+Proto*f;
+Table*h;
+struct FuncState*prev;
+struct LexState*ls;
+struct lua_State*L;
+struct BlockCnt*bl;
+int pc;
+int lasttarget;
+int jpc;
+int freereg;
+int nk;
+int np;
+short nlocvars;
+lu_byte nactvar;
+upvaldesc upvalues[60];
+unsigned short actvar[200];
+}FuncState;
+static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff,
+const char*name);
+struct lua_longjmp{
+struct lua_longjmp*previous;
+jmp_buf b;
+volatile int status;
+};
+static void luaD_seterrorobj(lua_State*L,int errcode,StkId oldtop){
+switch(errcode){
+case 4:{
+setsvalue(L,oldtop,luaS_newliteral(L,"not enough memory"));
+break;
+}
+case 5:{
+setsvalue(L,oldtop,luaS_newliteral(L,"error in error handling"));
+break;
+}
+case 3:
+case 2:{
+setobj(L,oldtop,L->top-1);
+break;
+}
+}
+L->top=oldtop+1;
+}
+static void restore_stack_limit(lua_State*L){
+if(L->size_ci>20000){
+int inuse=cast_int(L->ci-L->base_ci);
+if(inuse+1<20000)
+luaD_reallocCI(L,20000);
+}
+}
+static void resetstack(lua_State*L,int status){
+L->ci=L->base_ci;
+L->base=L->ci->base;
+luaF_close(L,L->base);
+luaD_seterrorobj(L,status,L->base);
+L->nCcalls=L->baseCcalls;
+L->allowhook=1;
+restore_stack_limit(L);
+L->errfunc=0;
+L->errorJmp=NULL;
+}
+static void luaD_throw(lua_State*L,int errcode){
+if(L->errorJmp){
+L->errorJmp->status=errcode;
+LUAI_THROW(L,L->errorJmp);
+}
+else{
+L->status=cast_byte(errcode);
+if(G(L)->panic){
+resetstack(L,errcode);
+G(L)->panic(L);
+}
+exit(EXIT_FAILURE);
+}
+}
+static int luaD_rawrunprotected(lua_State*L,Pfunc f,void*ud){
+struct lua_longjmp lj;
+lj.status=0;
+lj.previous=L->errorJmp;
+L->errorJmp=&lj;
+LUAI_TRY(L,&lj,
+(*f)(L,ud);
+);
+L->errorJmp=lj.previous;
+return lj.status;
+}
+static void correctstack(lua_State*L,TValue*oldstack){
+CallInfo*ci;
+GCObject*up;
+L->top=(L->top-oldstack)+L->stack;
+for(up=L->openupval;up!=NULL;up=up->gch.next)
+gco2uv(up)->v=(gco2uv(up)->v-oldstack)+L->stack;
+for(ci=L->base_ci;ci<=L->ci;ci++){
+ci->top=(ci->top-oldstack)+L->stack;
+ci->base=(ci->base-oldstack)+L->stack;
+ci->func=(ci->func-oldstack)+L->stack;
+}
+L->base=(L->base-oldstack)+L->stack;
+}
+static void luaD_reallocstack(lua_State*L,int newsize){
+TValue*oldstack=L->stack;
+int realsize=newsize+1+5;
+luaM_reallocvector(L,L->stack,L->stacksize,realsize,TValue);
+L->stacksize=realsize;
+L->stack_last=L->stack+newsize;
+correctstack(L,oldstack);
+}
+static void luaD_reallocCI(lua_State*L,int newsize){
+CallInfo*oldci=L->base_ci;
+luaM_reallocvector(L,L->base_ci,L->size_ci,newsize,CallInfo);
+L->size_ci=newsize;
+L->ci=(L->ci-oldci)+L->base_ci;
+L->end_ci=L->base_ci+L->size_ci-1;
+}
+static void luaD_growstack(lua_State*L,int n){
+if(n<=L->stacksize)
+luaD_reallocstack(L,2*L->stacksize);
+else
+luaD_reallocstack(L,L->stacksize+n);
+}
+static CallInfo*growCI(lua_State*L){
+if(L->size_ci>20000)
+luaD_throw(L,5);
+else{
+luaD_reallocCI(L,2*L->size_ci);
+if(L->size_ci>20000)
+luaG_runerror(L,"stack overflow");
+}
+return++L->ci;
+}
+static StkId adjust_varargs(lua_State*L,Proto*p,int actual){
+int i;
+int nfixargs=p->numparams;
+Table*htab=NULL;
+StkId base,fixed;
+for(;actual<nfixargs;++actual)
+setnilvalue(L->top++);
+fixed=L->top-actual;
+base=L->top;
+for(i=0;i<nfixargs;i++){
+setobj(L,L->top++,fixed+i);
+setnilvalue(fixed+i);
+}
+if(htab){
+sethvalue(L,L->top++,htab);
+}
+return base;
+}
+static StkId tryfuncTM(lua_State*L,StkId func){
+const TValue*tm=luaT_gettmbyobj(L,func,TM_CALL);
+StkId p;
+ptrdiff_t funcr=savestack(L,func);
+if(!ttisfunction(tm))
+luaG_typeerror(L,func,"call");
+for(p=L->top;p>func;p--)setobj(L,p,p-1);
+incr_top(L);
+func=restorestack(L,funcr);
+setobj(L,func,tm);
+return func;
+}
+#define inc_ci(L)((L->ci==L->end_ci)?growCI(L):(condhardstacktests(luaD_reallocCI(L,L->size_ci)),++L->ci))
+static int luaD_precall(lua_State*L,StkId func,int nresults){
+LClosure*cl;
+ptrdiff_t funcr;
+if(!ttisfunction(func))
+func=tryfuncTM(L,func);
+funcr=savestack(L,func);
+cl=&clvalue(func)->l;
+L->ci->savedpc=L->savedpc;
+if(!cl->isC){
+CallInfo*ci;
+StkId st,base;
+Proto*p=cl->p;
+luaD_checkstack(L,p->maxstacksize);
+func=restorestack(L,funcr);
+if(!p->is_vararg){
+base=func+1;
+if(L->top>base+p->numparams)
+L->top=base+p->numparams;
+}
+else{
+int nargs=cast_int(L->top-func)-1;
+base=adjust_varargs(L,p,nargs);
+func=restorestack(L,funcr);
+}
+ci=inc_ci(L);
+ci->func=func;
+L->base=ci->base=base;
+ci->top=L->base+p->maxstacksize;
+L->savedpc=p->code;
+ci->tailcalls=0;
+ci->nresults=nresults;
+for(st=L->top;st<ci->top;st++)
+setnilvalue(st);
+L->top=ci->top;
+return 0;
+}
+else{
+CallInfo*ci;
+int n;
+luaD_checkstack(L,20);
+ci=inc_ci(L);
+ci->func=restorestack(L,funcr);
+L->base=ci->base=ci->func+1;
+ci->top=L->top+20;
+ci->nresults=nresults;
+n=(*curr_func(L)->c.f)(L);
+if(n<0)
+return 2;
+else{
+luaD_poscall(L,L->top-n);
+return 1;
+}
+}
+}
+static int luaD_poscall(lua_State*L,StkId firstResult){
+StkId res;
+int wanted,i;
+CallInfo*ci;
+ci=L->ci--;
+res=ci->func;
+wanted=ci->nresults;
+L->base=(ci-1)->base;
+L->savedpc=(ci-1)->savedpc;
+for(i=wanted;i!=0&&firstResult<L->top;i--)
+setobj(L,res++,firstResult++);
+while(i-->0)
+setnilvalue(res++);
+L->top=res;
+return(wanted-(-1));
+}
+static void luaD_call(lua_State*L,StkId func,int nResults){
+if(++L->nCcalls>=200){
+if(L->nCcalls==200)
+luaG_runerror(L,"C stack overflow");
+else if(L->nCcalls>=(200+(200>>3)))
+luaD_throw(L,5);
+}
+if(luaD_precall(L,func,nResults)==0)
+luaV_execute(L,1);
+L->nCcalls--;
+luaC_checkGC(L);
+}
+static int luaD_pcall(lua_State*L,Pfunc func,void*u,
+ptrdiff_t old_top,ptrdiff_t ef){
+int status;
+unsigned short oldnCcalls=L->nCcalls;
+ptrdiff_t old_ci=saveci(L,L->ci);
+lu_byte old_allowhooks=L->allowhook;
+ptrdiff_t old_errfunc=L->errfunc;
+L->errfunc=ef;
+status=luaD_rawrunprotected(L,func,u);
+if(status!=0){
+StkId oldtop=restorestack(L,old_top);
+luaF_close(L,oldtop);
+luaD_seterrorobj(L,status,oldtop);
+L->nCcalls=oldnCcalls;
+L->ci=restoreci(L,old_ci);
+L->base=L->ci->base;
+L->savedpc=L->ci->savedpc;
+L->allowhook=old_allowhooks;
+restore_stack_limit(L);
+}
+L->errfunc=old_errfunc;
+return status;
+}
+struct SParser{
+ZIO*z;
+Mbuffer buff;
+const char*name;
+};
+static void f_parser(lua_State*L,void*ud){
+int i;
+Proto*tf;
+Closure*cl;
+struct SParser*p=cast(struct SParser*,ud);
+luaC_checkGC(L);
+tf=luaY_parser(L,p->z,
+&p->buff,p->name);
+cl=luaF_newLclosure(L,tf->nups,hvalue(gt(L)));
+cl->l.p=tf;
+for(i=0;i<tf->nups;i++)
+cl->l.upvals[i]=luaF_newupval(L);
+setclvalue(L,L->top,cl);
+incr_top(L);
+}
+static int luaD_protectedparser(lua_State*L,ZIO*z,const char*name){
+struct SParser p;
+int status;
+p.z=z;p.name=name;
+luaZ_initbuffer(L,&p.buff);
+status=luaD_pcall(L,f_parser,&p,savestack(L,L->top),L->errfunc);
+luaZ_freebuffer(L,&p.buff);
+return status;
+}
+static void luaS_resize(lua_State*L,int newsize){
+GCObject**newhash;
+stringtable*tb;
+int i;
+if(G(L)->gcstate==2)
+return;
+newhash=luaM_newvector(L,newsize,GCObject*);
+tb=&G(L)->strt;
+for(i=0;i<newsize;i++)newhash[i]=NULL;
+for(i=0;i<tb->size;i++){
+GCObject*p=tb->hash[i];
+while(p){
+GCObject*next=p->gch.next;
+unsigned int h=gco2ts(p)->hash;
+int h1=lmod(h,newsize);
+p->gch.next=newhash[h1];
+newhash[h1]=p;
+p=next;
+}
+}
+luaM_freearray(L,tb->hash,tb->size,TString*);
+tb->size=newsize;
+tb->hash=newhash;
+}
+static TString*newlstr(lua_State*L,const char*str,size_t l,
+unsigned int h){
+TString*ts;
+stringtable*tb;
+if(l+1>(((size_t)(~(size_t)0)-2)-sizeof(TString))/sizeof(char))
+luaM_toobig(L);
+ts=cast(TString*,luaM_malloc(L,(l+1)*sizeof(char)+sizeof(TString)));
+ts->tsv.len=l;
+ts->tsv.hash=h;
+ts->tsv.marked=luaC_white(G(L));
+ts->tsv.tt=4;
+ts->tsv.reserved=0;
+memcpy(ts+1,str,l*sizeof(char));
+((char*)(ts+1))[l]='\0';
+tb=&G(L)->strt;
+h=lmod(h,tb->size);
+ts->tsv.next=tb->hash[h];
+tb->hash[h]=obj2gco(ts);
+tb->nuse++;
+if(tb->nuse>cast(lu_int32,tb->size)&&tb->size<=(INT_MAX-2)/2)
+luaS_resize(L,tb->size*2);
+return ts;
+}
+static TString*luaS_newlstr(lua_State*L,const char*str,size_t l){
+GCObject*o;
+unsigned int h=cast(unsigned int,l);
+size_t step=(l>>5)+1;
+size_t l1;
+for(l1=l;l1>=step;l1-=step)
+h=h^((h<<5)+(h>>2)+cast(unsigned char,str[l1-1]));
+for(o=G(L)->strt.hash[lmod(h,G(L)->strt.size)];
+o!=NULL;
+o=o->gch.next){
+TString*ts=rawgco2ts(o);
+if(ts->tsv.len==l&&(memcmp(str,getstr(ts),l)==0)){
+if(isdead(G(L),o))changewhite(o);
+return ts;
+}
+}
+return newlstr(L,str,l,h);
+}
+static Udata*luaS_newudata(lua_State*L,size_t s,Table*e){
+Udata*u;
+if(s>((size_t)(~(size_t)0)-2)-sizeof(Udata))
+luaM_toobig(L);
+u=cast(Udata*,luaM_malloc(L,s+sizeof(Udata)));
+u->uv.marked=luaC_white(G(L));
+u->uv.tt=7;
+u->uv.len=s;
+u->uv.metatable=NULL;
+u->uv.env=e;
+u->uv.next=G(L)->mainthread->next;
+G(L)->mainthread->next=obj2gco(u);
+return u;
+}
+#define hashpow2(t,n)(gnode(t,lmod((n),sizenode(t))))
+#define hashstr(t,str)hashpow2(t,(str)->tsv.hash)
+#define hashboolean(t,p)hashpow2(t,p)
+#define hashmod(t,n)(gnode(t,((n)%((sizenode(t)-1)|1))))
+#define hashpointer(t,p)hashmod(t,IntPoint(p))
+static const Node dummynode_={
+{{NULL},0},
+{{{NULL},0,NULL}}
+};
+static Node*hashnum(const Table*t,lua_Number n){
+unsigned int a[cast_int(sizeof(lua_Number)/sizeof(int))];
+int i;
+if(luai_numeq(n,0))
+return gnode(t,0);
+memcpy(a,&n,sizeof(a));
+for(i=1;i<cast_int(sizeof(lua_Number)/sizeof(int));i++)a[0]+=a[i];
+return hashmod(t,a[0]);
+}
+static Node*mainposition(const Table*t,const TValue*key){
+switch(ttype(key)){
+case 3:
+return hashnum(t,nvalue(key));
+case 4:
+return hashstr(t,rawtsvalue(key));
+case 1:
+return hashboolean(t,bvalue(key));
+case 2:
+return hashpointer(t,pvalue(key));
+default:
+return hashpointer(t,gcvalue(key));
+}
+}
+static int arrayindex(const TValue*key){
+if(ttisnumber(key)){
+lua_Number n=nvalue(key);
+int k;
+lua_number2int(k,n);
+if(luai_numeq(cast_num(k),n))
+return k;
+}
+return-1;
+}
+static int findindex(lua_State*L,Table*t,StkId key){
+int i;
+if(ttisnil(key))return-1;
+i=arrayindex(key);
+if(0<i&&i<=t->sizearray)
+return i-1;
+else{
+Node*n=mainposition(t,key);
+do{
+if(luaO_rawequalObj(key2tval(n),key)||
+(ttype(gkey(n))==(8+3)&&iscollectable(key)&&
+gcvalue(gkey(n))==gcvalue(key))){
+i=cast_int(n-gnode(t,0));
+return i+t->sizearray;
+}
+else n=gnext(n);
+}while(n);
+luaG_runerror(L,"invalid key to "LUA_QL("next"));
+return 0;
+}
+}
+static int luaH_next(lua_State*L,Table*t,StkId key){
+int i=findindex(L,t,key);
+for(i++;i<t->sizearray;i++){
+if(!ttisnil(&t->array[i])){
+setnvalue(key,cast_num(i+1));
+setobj(L,key+1,&t->array[i]);
+return 1;
+}
+}
+for(i-=t->sizearray;i<(int)sizenode(t);i++){
+if(!ttisnil(gval(gnode(t,i)))){
+setobj(L,key,key2tval(gnode(t,i)));
+setobj(L,key+1,gval(gnode(t,i)));
+return 1;
+}
+}
+return 0;
+}
+static int computesizes(int nums[],int*narray){
+int i;
+int twotoi;
+int a=0;
+int na=0;
+int n=0;
+for(i=0,twotoi=1;twotoi/2<*narray;i++,twotoi*=2){
+if(nums[i]>0){
+a+=nums[i];
+if(a>twotoi/2){
+n=twotoi;
+na=a;
+}
+}
+if(a==*narray)break;
+}
+*narray=n;
+return na;
+}
+static int countint(const TValue*key,int*nums){
+int k=arrayindex(key);
+if(0<k&&k<=(1<<(32-2))){
+nums[ceillog2(k)]++;
+return 1;
+}
+else
+return 0;
+}
+static int numusearray(const Table*t,int*nums){
+int lg;
+int ttlg;
+int ause=0;
+int i=1;
+for(lg=0,ttlg=1;lg<=(32-2);lg++,ttlg*=2){
+int lc=0;
+int lim=ttlg;
+if(lim>t->sizearray){
+lim=t->sizearray;
+if(i>lim)
+break;
+}
+for(;i<=lim;i++){
+if(!ttisnil(&t->array[i-1]))
+lc++;
+}
+nums[lg]+=lc;
+ause+=lc;
+}
+return ause;
+}
+static int numusehash(const Table*t,int*nums,int*pnasize){
+int totaluse=0;
+int ause=0;
+int i=sizenode(t);
+while(i--){
+Node*n=&t->node[i];
+if(!ttisnil(gval(n))){
+ause+=countint(key2tval(n),nums);
+totaluse++;
+}
+}
+*pnasize+=ause;
+return totaluse;
+}
+static void setarrayvector(lua_State*L,Table*t,int size){
+int i;
+luaM_reallocvector(L,t->array,t->sizearray,size,TValue);
+for(i=t->sizearray;i<size;i++)
+setnilvalue(&t->array[i]);
+t->sizearray=size;
+}
+static void setnodevector(lua_State*L,Table*t,int size){
+int lsize;
+if(size==0){
+t->node=cast(Node*,(&dummynode_));
+lsize=0;
+}
+else{
+int i;
+lsize=ceillog2(size);
+if(lsize>(32-2))
+luaG_runerror(L,"table overflow");
+size=twoto(lsize);
+t->node=luaM_newvector(L,size,Node);
+for(i=0;i<size;i++){
+Node*n=gnode(t,i);
+gnext(n)=NULL;
+setnilvalue(gkey(n));
+setnilvalue(gval(n));
+}
+}
+t->lsizenode=cast_byte(lsize);
+t->lastfree=gnode(t,size);
+}
+static void resize(lua_State*L,Table*t,int nasize,int nhsize){
+int i;
+int oldasize=t->sizearray;
+int oldhsize=t->lsizenode;
+Node*nold=t->node;
+if(nasize>oldasize)
+setarrayvector(L,t,nasize);
+setnodevector(L,t,nhsize);
+if(nasize<oldasize){
+t->sizearray=nasize;
+for(i=nasize;i<oldasize;i++){
+if(!ttisnil(&t->array[i]))
+setobj(L,luaH_setnum(L,t,i+1),&t->array[i]);
+}
+luaM_reallocvector(L,t->array,oldasize,nasize,TValue);
+}
+for(i=twoto(oldhsize)-1;i>=0;i--){
+Node*old=nold+i;
+if(!ttisnil(gval(old)))
+setobj(L,luaH_set(L,t,key2tval(old)),gval(old));
+}
+if(nold!=(&dummynode_))
+luaM_freearray(L,nold,twoto(oldhsize),Node);
+}
+static void luaH_resizearray(lua_State*L,Table*t,int nasize){
+int nsize=(t->node==(&dummynode_))?0:sizenode(t);
+resize(L,t,nasize,nsize);
+}
+static void rehash(lua_State*L,Table*t,const TValue*ek){
+int nasize,na;
+int nums[(32-2)+1];
+int i;
+int totaluse;
+for(i=0;i<=(32-2);i++)nums[i]=0;
+nasize=numusearray(t,nums);
+totaluse=nasize;
+totaluse+=numusehash(t,nums,&nasize);
+nasize+=countint(ek,nums);
+totaluse++;
+na=computesizes(nums,&nasize);
+resize(L,t,nasize,totaluse-na);
+}
+static Table*luaH_new(lua_State*L,int narray,int nhash){
+Table*t=luaM_new(L,Table);
+luaC_link(L,obj2gco(t),5);
+t->metatable=NULL;
+t->flags=cast_byte(~0);
+t->array=NULL;
+t->sizearray=0;
+t->lsizenode=0;
+t->node=cast(Node*,(&dummynode_));
+setarrayvector(L,t,narray);
+setnodevector(L,t,nhash);
+return t;
+}
+static void luaH_free(lua_State*L,Table*t){
+if(t->node!=(&dummynode_))
+luaM_freearray(L,t->node,sizenode(t),Node);
+luaM_freearray(L,t->array,t->sizearray,TValue);
+luaM_free(L,t);
+}
+static Node*getfreepos(Table*t){
+while(t->lastfree-->t->node){
+if(ttisnil(gkey(t->lastfree)))
+return t->lastfree;
+}
+return NULL;
+}
+static TValue*newkey(lua_State*L,Table*t,const TValue*key){
+Node*mp=mainposition(t,key);
+if(!ttisnil(gval(mp))||mp==(&dummynode_)){
+Node*othern;
+Node*n=getfreepos(t);
+if(n==NULL){
+rehash(L,t,key);
+return luaH_set(L,t,key);
+}
+othern=mainposition(t,key2tval(mp));
+if(othern!=mp){
+while(gnext(othern)!=mp)othern=gnext(othern);
+gnext(othern)=n;
+*n=*mp;
+gnext(mp)=NULL;
+setnilvalue(gval(mp));
+}
+else{
+gnext(n)=gnext(mp);
+gnext(mp)=n;
+mp=n;
+}
+}
+gkey(mp)->value=key->value;gkey(mp)->tt=key->tt;
+luaC_barriert(L,t,key);
+return gval(mp);
+}
+static const TValue*luaH_getnum(Table*t,int key){
+if(cast(unsigned int,key)-1<cast(unsigned int,t->sizearray))
+return&t->array[key-1];
+else{
+lua_Number nk=cast_num(key);
+Node*n=hashnum(t,nk);
+do{
+if(ttisnumber(gkey(n))&&luai_numeq(nvalue(gkey(n)),nk))
+return gval(n);
+else n=gnext(n);
+}while(n);
+return(&luaO_nilobject_);
+}
+}
+static const TValue*luaH_getstr(Table*t,TString*key){
+Node*n=hashstr(t,key);
+do{
+if(ttisstring(gkey(n))&&rawtsvalue(gkey(n))==key)
+return gval(n);
+else n=gnext(n);
+}while(n);
+return(&luaO_nilobject_);
+}
+static const TValue*luaH_get(Table*t,const TValue*key){
+switch(ttype(key)){
+case 0:return(&luaO_nilobject_);
+case 4:return luaH_getstr(t,rawtsvalue(key));
+case 3:{
+int k;
+lua_Number n=nvalue(key);
+lua_number2int(k,n);
+if(luai_numeq(cast_num(k),nvalue(key)))
+return luaH_getnum(t,k);
+}
+default:{
+Node*n=mainposition(t,key);
+do{
+if(luaO_rawequalObj(key2tval(n),key))
+return gval(n);
+else n=gnext(n);
+}while(n);
+return(&luaO_nilobject_);
+}
+}
+}
+static TValue*luaH_set(lua_State*L,Table*t,const TValue*key){
+const TValue*p=luaH_get(t,key);
+t->flags=0;
+if(p!=(&luaO_nilobject_))
+return cast(TValue*,p);
+else{
+if(ttisnil(key))luaG_runerror(L,"table index is nil");
+else if(ttisnumber(key)&&luai_numisnan(nvalue(key)))
+luaG_runerror(L,"table index is NaN");
+return newkey(L,t,key);
+}
+}
+static TValue*luaH_setnum(lua_State*L,Table*t,int key){
+const TValue*p=luaH_getnum(t,key);
+if(p!=(&luaO_nilobject_))
+return cast(TValue*,p);
+else{
+TValue k;
+setnvalue(&k,cast_num(key));
+return newkey(L,t,&k);
+}
+}
+static TValue*luaH_setstr(lua_State*L,Table*t,TString*key){
+const TValue*p=luaH_getstr(t,key);
+if(p!=(&luaO_nilobject_))
+return cast(TValue*,p);
+else{
+TValue k;
+setsvalue(L,&k,key);
+return newkey(L,t,&k);
+}
+}
+static int unbound_search(Table*t,unsigned int j){
+unsigned int i=j;
+j++;
+while(!ttisnil(luaH_getnum(t,j))){
+i=j;
+j*=2;
+if(j>cast(unsigned int,(INT_MAX-2))){
+i=1;
+while(!ttisnil(luaH_getnum(t,i)))i++;
+return i-1;
+}
+}
+while(j-i>1){
+unsigned int m=(i+j)/2;
+if(ttisnil(luaH_getnum(t,m)))j=m;
+else i=m;
+}
+return i;
+}
+static int luaH_getn(Table*t){
+unsigned int j=t->sizearray;
+if(j>0&&ttisnil(&t->array[j-1])){
+unsigned int i=0;
+while(j-i>1){
+unsigned int m=(i+j)/2;
+if(ttisnil(&t->array[m-1]))j=m;
+else i=m;
+}
+return i;
+}
+else if(t->node==(&dummynode_))
+return j;
+else return unbound_search(t,j);
+}
+#define makewhite(g,x)((x)->gch.marked=cast_byte(((x)->gch.marked&cast_byte(~(bitmask(2)|bit2mask(0,1))))|luaC_white(g)))
+#define white2gray(x)reset2bits((x)->gch.marked,0,1)
+#define black2gray(x)resetbit((x)->gch.marked,2)
+#define stringmark(s)reset2bits((s)->tsv.marked,0,1)
+#define isfinalized(u)testbit((u)->marked,3)
+#define markfinalized(u)l_setbit((u)->marked,3)
+#define markvalue(g,o){checkconsistency(o);if(iscollectable(o)&&iswhite(gcvalue(o)))reallymarkobject(g,gcvalue(o));}
+#define markobject(g,t){if(iswhite(obj2gco(t)))reallymarkobject(g,obj2gco(t));}
+#define setthreshold(g)(g->GCthreshold=(g->estimate/100)*g->gcpause)
+static void removeentry(Node*n){
+if(iscollectable(gkey(n)))
+setttype(gkey(n),(8+3));
+}
+static void reallymarkobject(global_State*g,GCObject*o){
+white2gray(o);
+switch(o->gch.tt){
+case 4:{
+return;
+}
+case 7:{
+Table*mt=gco2u(o)->metatable;
+gray2black(o);
+if(mt)markobject(g,mt);
+markobject(g,gco2u(o)->env);
+return;
+}
+case(8+2):{
+UpVal*uv=gco2uv(o);
+markvalue(g,uv->v);
+if(uv->v==&uv->u.value)
+gray2black(o);
+return;
+}
+case 6:{
+gco2cl(o)->c.gclist=g->gray;
+g->gray=o;
+break;
+}
+case 5:{
+gco2h(o)->gclist=g->gray;
+g->gray=o;
+break;
+}
+case 8:{
+gco2th(o)->gclist=g->gray;
+g->gray=o;
+break;
+}
+case(8+1):{
+gco2p(o)->gclist=g->gray;
+g->gray=o;
+break;
+}
+default:;
+}
+}
+static void marktmu(global_State*g){
+GCObject*u=g->tmudata;
+if(u){
+do{
+u=u->gch.next;
+makewhite(g,u);
+reallymarkobject(g,u);
+}while(u!=g->tmudata);
+}
+}
+static size_t luaC_separateudata(lua_State*L,int all){
+global_State*g=G(L);
+size_t deadmem=0;
+GCObject**p=&g->mainthread->next;
+GCObject*curr;
+while((curr=*p)!=NULL){
+if(!(iswhite(curr)||all)||isfinalized(gco2u(curr)))
+p=&curr->gch.next;
+else if(fasttm(L,gco2u(curr)->metatable,TM_GC)==NULL){
+markfinalized(gco2u(curr));
+p=&curr->gch.next;
+}
+else{
+deadmem+=sizeudata(gco2u(curr));
+markfinalized(gco2u(curr));
+*p=curr->gch.next;
+if(g->tmudata==NULL)
+g->tmudata=curr->gch.next=curr;
+else{
+curr->gch.next=g->tmudata->gch.next;
+g->tmudata->gch.next=curr;
+g->tmudata=curr;
+}
+}
+}
+return deadmem;
+}
+static int traversetable(global_State*g,Table*h){
+int i;
+int weakkey=0;
+int weakvalue=0;
+const TValue*mode;
+if(h->metatable)
+markobject(g,h->metatable);
+mode=gfasttm(g,h->metatable,TM_MODE);
+if(mode&&ttisstring(mode)){
+weakkey=(strchr(svalue(mode),'k')!=NULL);
+weakvalue=(strchr(svalue(mode),'v')!=NULL);
+if(weakkey||weakvalue){
+h->marked&=~(bitmask(3)|bitmask(4));
+h->marked|=cast_byte((weakkey<<3)|
+(weakvalue<<4));
+h->gclist=g->weak;
+g->weak=obj2gco(h);
+}
+}
+if(weakkey&&weakvalue)return 1;
+if(!weakvalue){
+i=h->sizearray;
+while(i--)
+markvalue(g,&h->array[i]);
+}
+i=sizenode(h);
+while(i--){
+Node*n=gnode(h,i);
+if(ttisnil(gval(n)))
+removeentry(n);
+else{
+if(!weakkey)markvalue(g,gkey(n));
+if(!weakvalue)markvalue(g,gval(n));
+}
+}
+return weakkey||weakvalue;
+}
+static void traverseproto(global_State*g,Proto*f){
+int i;
+if(f->source)stringmark(f->source);
+for(i=0;i<f->sizek;i++)
+markvalue(g,&f->k[i]);
+for(i=0;i<f->sizeupvalues;i++){
+if(f->upvalues[i])
+stringmark(f->upvalues[i]);
+}
+for(i=0;i<f->sizep;i++){
+if(f->p[i])
+markobject(g,f->p[i]);
+}
+for(i=0;i<f->sizelocvars;i++){
+if(f->locvars[i].varname)
+stringmark(f->locvars[i].varname);
+}
+}
+static void traverseclosure(global_State*g,Closure*cl){
+markobject(g,cl->c.env);
+if(cl->c.isC){
+int i;
+for(i=0;i<cl->c.nupvalues;i++)
+markvalue(g,&cl->c.upvalue[i]);
+}
+else{
+int i;
+markobject(g,cl->l.p);
+for(i=0;i<cl->l.nupvalues;i++)
+markobject(g,cl->l.upvals[i]);
+}
+}
+static void checkstacksizes(lua_State*L,StkId max){
+int ci_used=cast_int(L->ci-L->base_ci);
+int s_used=cast_int(max-L->stack);
+if(L->size_ci>20000)
+return;
+if(4*ci_used<L->size_ci&&2*8<L->size_ci)
+luaD_reallocCI(L,L->size_ci/2);
+condhardstacktests(luaD_reallocCI(L,ci_used+1));
+if(4*s_used<L->stacksize&&
+2*((2*20)+5)<L->stacksize)
+luaD_reallocstack(L,L->stacksize/2);
+condhardstacktests(luaD_reallocstack(L,s_used));
+}
+static void traversestack(global_State*g,lua_State*l){
+StkId o,lim;
+CallInfo*ci;
+markvalue(g,gt(l));
+lim=l->top;
+for(ci=l->base_ci;ci<=l->ci;ci++){
+if(lim<ci->top)lim=ci->top;
+}
+for(o=l->stack;o<l->top;o++)
+markvalue(g,o);
+for(;o<=lim;o++)
+setnilvalue(o);
+checkstacksizes(l,lim);
+}
+static l_mem propagatemark(global_State*g){
+GCObject*o=g->gray;
+gray2black(o);
+switch(o->gch.tt){
+case 5:{
+Table*h=gco2h(o);
+g->gray=h->gclist;
+if(traversetable(g,h))
+black2gray(o);
+return sizeof(Table)+sizeof(TValue)*h->sizearray+
+sizeof(Node)*sizenode(h);
+}
+case 6:{
+Closure*cl=gco2cl(o);
+g->gray=cl->c.gclist;
+traverseclosure(g,cl);
+return(cl->c.isC)?sizeCclosure(cl->c.nupvalues):
+sizeLclosure(cl->l.nupvalues);
+}
+case 8:{
+lua_State*th=gco2th(o);
+g->gray=th->gclist;
+th->gclist=g->grayagain;
+g->grayagain=o;
+black2gray(o);
+traversestack(g,th);
+return sizeof(lua_State)+sizeof(TValue)*th->stacksize+
+sizeof(CallInfo)*th->size_ci;
+}
+case(8+1):{
+Proto*p=gco2p(o);
+g->gray=p->gclist;
+traverseproto(g,p);
+return sizeof(Proto)+sizeof(Instruction)*p->sizecode+
+sizeof(Proto*)*p->sizep+
+sizeof(TValue)*p->sizek+
+sizeof(int)*p->sizelineinfo+
+sizeof(LocVar)*p->sizelocvars+
+sizeof(TString*)*p->sizeupvalues;
+}
+default:return 0;
+}
+}
+static size_t propagateall(global_State*g){
+size_t m=0;
+while(g->gray)m+=propagatemark(g);
+return m;
+}
+static int iscleared(const TValue*o,int iskey){
+if(!iscollectable(o))return 0;
+if(ttisstring(o)){
+stringmark(rawtsvalue(o));
+return 0;
+}
+return iswhite(gcvalue(o))||
+(ttisuserdata(o)&&(!iskey&&isfinalized(uvalue(o))));
+}
+static void cleartable(GCObject*l){
+while(l){
+Table*h=gco2h(l);
+int i=h->sizearray;
+if(testbit(h->marked,4)){
+while(i--){
+TValue*o=&h->array[i];
+if(iscleared(o,0))
+setnilvalue(o);
+}
+}
+i=sizenode(h);
+while(i--){
+Node*n=gnode(h,i);
+if(!ttisnil(gval(n))&&
+(iscleared(key2tval(n),1)||iscleared(gval(n),0))){
+setnilvalue(gval(n));
+removeentry(n);
+}
+}
+l=h->gclist;
+}
+}
+static void freeobj(lua_State*L,GCObject*o){
+switch(o->gch.tt){
+case(8+1):luaF_freeproto(L,gco2p(o));break;
+case 6:luaF_freeclosure(L,gco2cl(o));break;
+case(8+2):luaF_freeupval(L,gco2uv(o));break;
+case 5:luaH_free(L,gco2h(o));break;
+case 8:{
+luaE_freethread(L,gco2th(o));
+break;
+}
+case 4:{
+G(L)->strt.nuse--;
+luaM_freemem(L,o,sizestring(gco2ts(o)));
+break;
+}
+case 7:{
+luaM_freemem(L,o,sizeudata(gco2u(o)));
+break;
+}
+default:;
+}
+}
+#define sweepwholelist(L,p)sweeplist(L,p,((lu_mem)(~(lu_mem)0)-2))
+static GCObject**sweeplist(lua_State*L,GCObject**p,lu_mem count){
+GCObject*curr;
+global_State*g=G(L);
+int deadmask=otherwhite(g);
+while((curr=*p)!=NULL&&count-->0){
+if(curr->gch.tt==8)
+sweepwholelist(L,&gco2th(curr)->openupval);
+if((curr->gch.marked^bit2mask(0,1))&deadmask){
+makewhite(g,curr);
+p=&curr->gch.next;
+}
+else{
+*p=curr->gch.next;
+if(curr==g->rootgc)
+g->rootgc=curr->gch.next;
+freeobj(L,curr);
+}
+}
+return p;
+}
+static void checkSizes(lua_State*L){
+global_State*g=G(L);
+if(g->strt.nuse<cast(lu_int32,g->strt.size/4)&&
+g->strt.size>32*2)
+luaS_resize(L,g->strt.size/2);
+if(luaZ_sizebuffer(&g->buff)>32*2){
+size_t newsize=luaZ_sizebuffer(&g->buff)/2;
+luaZ_resizebuffer(L,&g->buff,newsize);
+}
+}
+static void GCTM(lua_State*L){
+global_State*g=G(L);
+GCObject*o=g->tmudata->gch.next;
+Udata*udata=rawgco2u(o);
+const TValue*tm;
+if(o==g->tmudata)
+g->tmudata=NULL;
+else
+g->tmudata->gch.next=udata->uv.next;
+udata->uv.next=g->mainthread->next;
+g->mainthread->next=o;
+makewhite(g,o);
+tm=fasttm(L,udata->uv.metatable,TM_GC);
+if(tm!=NULL){
+lu_byte oldah=L->allowhook;
+lu_mem oldt=g->GCthreshold;
+L->allowhook=0;
+g->GCthreshold=2*g->totalbytes;
+setobj(L,L->top,tm);
+setuvalue(L,L->top+1,udata);
+L->top+=2;
+luaD_call(L,L->top-2,0);
+L->allowhook=oldah;
+g->GCthreshold=oldt;
+}
+}
+static void luaC_callGCTM(lua_State*L){
+while(G(L)->tmudata)
+GCTM(L);
+}
+static void luaC_freeall(lua_State*L){
+global_State*g=G(L);
+int i;
+g->currentwhite=bit2mask(0,1)|bitmask(6);
+sweepwholelist(L,&g->rootgc);
+for(i=0;i<g->strt.size;i++)
+sweepwholelist(L,&g->strt.hash[i]);
+}
+static void markmt(global_State*g){
+int i;
+for(i=0;i<(8+1);i++)
+if(g->mt[i])markobject(g,g->mt[i]);
+}
+static void markroot(lua_State*L){
+global_State*g=G(L);
+g->gray=NULL;
+g->grayagain=NULL;
+g->weak=NULL;
+markobject(g,g->mainthread);
+markvalue(g,gt(g->mainthread));
+markvalue(g,registry(L));
+markmt(g);
+g->gcstate=1;
+}
+static void remarkupvals(global_State*g){
+UpVal*uv;
+for(uv=g->uvhead.u.l.next;uv!=&g->uvhead;uv=uv->u.l.next){
+if(isgray(obj2gco(uv)))
+markvalue(g,uv->v);
+}
+}
+static void atomic(lua_State*L){
+global_State*g=G(L);
+size_t udsize;
+remarkupvals(g);
+propagateall(g);
+g->gray=g->weak;
+g->weak=NULL;
+markobject(g,L);
+markmt(g);
+propagateall(g);
+g->gray=g->grayagain;
+g->grayagain=NULL;
+propagateall(g);
+udsize=luaC_separateudata(L,0);
+marktmu(g);
+udsize+=propagateall(g);
+cleartable(g->weak);
+g->currentwhite=cast_byte(otherwhite(g));
+g->sweepstrgc=0;
+g->sweepgc=&g->rootgc;
+g->gcstate=2;
+g->estimate=g->totalbytes-udsize;
+}
+static l_mem singlestep(lua_State*L){
+global_State*g=G(L);
+switch(g->gcstate){
+case 0:{
+markroot(L);
+return 0;
+}
+case 1:{
+if(g->gray)
+return propagatemark(g);
+else{
+atomic(L);
+return 0;
+}
+}
+case 2:{
+lu_mem old=g->totalbytes;
+sweepwholelist(L,&g->strt.hash[g->sweepstrgc++]);
+if(g->sweepstrgc>=g->strt.size)
+g->gcstate=3;
+g->estimate-=old-g->totalbytes;
+return 10;
+}
+case 3:{
+lu_mem old=g->totalbytes;
+g->sweepgc=sweeplist(L,g->sweepgc,40);
+if(*g->sweepgc==NULL){
+checkSizes(L);
+g->gcstate=4;
+}
+g->estimate-=old-g->totalbytes;
+return 40*10;
+}
+case 4:{
+if(g->tmudata){
+GCTM(L);
+if(g->estimate>100)
+g->estimate-=100;
+return 100;
+}
+else{
+g->gcstate=0;
+g->gcdept=0;
+return 0;
+}
+}
+default:return 0;
+}
+}
+static void luaC_step(lua_State*L){
+global_State*g=G(L);
+l_mem lim=(1024u/100)*g->gcstepmul;
+if(lim==0)
+lim=(((lu_mem)(~(lu_mem)0)-2)-1)/2;
+g->gcdept+=g->totalbytes-g->GCthreshold;
+do{
+lim-=singlestep(L);
+if(g->gcstate==0)
+break;
+}while(lim>0);
+if(g->gcstate!=0){
+if(g->gcdept<1024u)
+g->GCthreshold=g->totalbytes+1024u;
+else{
+g->gcdept-=1024u;
+g->GCthreshold=g->totalbytes;
+}
+}
+else{
+setthreshold(g);
+}
+}
+static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v){
+global_State*g=G(L);
+if(g->gcstate==1)
+reallymarkobject(g,v);
+else
+makewhite(g,o);
+}
+static void luaC_barrierback(lua_State*L,Table*t){
+global_State*g=G(L);
+GCObject*o=obj2gco(t);
+black2gray(o);
+t->gclist=g->grayagain;
+g->grayagain=o;
+}
+static void luaC_link(lua_State*L,GCObject*o,lu_byte tt){
+global_State*g=G(L);
+o->gch.next=g->rootgc;
+g->rootgc=o;
+o->gch.marked=luaC_white(g);
+o->gch.tt=tt;
+}
+static void luaC_linkupval(lua_State*L,UpVal*uv){
+global_State*g=G(L);
+GCObject*o=obj2gco(uv);
+o->gch.next=g->rootgc;
+g->rootgc=o;
+if(isgray(o)){
+if(g->gcstate==1){
+gray2black(o);
+luaC_barrier(L,uv,uv->v);
+}
+else{
+makewhite(g,o);
+}
+}
+}
+typedef union{
+lua_Number r;
+TString*ts;
+}SemInfo;
+typedef struct Token{
+int token;
+SemInfo seminfo;
+}Token;
+typedef struct LexState{
+int current;
+int linenumber;
+int lastline;
+Token t;
+Token lookahead;
+struct FuncState*fs;
+struct lua_State*L;
+ZIO*z;
+Mbuffer*buff;
+TString*source;
+char decpoint;
+}LexState;
+static void luaX_init(lua_State*L);
+static void luaX_lexerror(LexState*ls,const char*msg,int token);
+#define state_size(x)(sizeof(x)+0)
+#define fromstate(l)(cast(lu_byte*,(l))-0)
+#define tostate(l)(cast(lua_State*,cast(lu_byte*,l)+0))
+typedef struct LG{
+lua_State l;
+global_State g;
+}LG;
+static void stack_init(lua_State*L1,lua_State*L){
+L1->base_ci=luaM_newvector(L,8,CallInfo);
+L1->ci=L1->base_ci;
+L1->size_ci=8;
+L1->end_ci=L1->base_ci+L1->size_ci-1;
+L1->stack=luaM_newvector(L,(2*20)+5,TValue);
+L1->stacksize=(2*20)+5;
+L1->top=L1->stack;
+L1->stack_last=L1->stack+(L1->stacksize-5)-1;
+L1->ci->func=L1->top;
+setnilvalue(L1->top++);
+L1->base=L1->ci->base=L1->top;
+L1->ci->top=L1->top+20;
+}
+static void freestack(lua_State*L,lua_State*L1){
+luaM_freearray(L,L1->base_ci,L1->size_ci,CallInfo);
+luaM_freearray(L,L1->stack,L1->stacksize,TValue);
+}
+static void f_luaopen(lua_State*L,void*ud){
+global_State*g=G(L);
+UNUSED(ud);
+stack_init(L,L);
+sethvalue(L,gt(L),luaH_new(L,0,2));
+sethvalue(L,registry(L),luaH_new(L,0,2));
+luaS_resize(L,32);
+luaT_init(L);
+luaX_init(L);
+luaS_fix(luaS_newliteral(L,"not enough memory"));
+g->GCthreshold=4*g->totalbytes;
+}
+static void preinit_state(lua_State*L,global_State*g){
+G(L)=g;
+L->stack=NULL;
+L->stacksize=0;
+L->errorJmp=NULL;
+L->hook=NULL;
+L->hookmask=0;
+L->basehookcount=0;
+L->allowhook=1;
+resethookcount(L);
+L->openupval=NULL;
+L->size_ci=0;
+L->nCcalls=L->baseCcalls=0;
+L->status=0;
+L->base_ci=L->ci=NULL;
+L->savedpc=NULL;
+L->errfunc=0;
+setnilvalue(gt(L));
+}
+static void close_state(lua_State*L){
+global_State*g=G(L);
+luaF_close(L,L->stack);
+luaC_freeall(L);
+luaM_freearray(L,G(L)->strt.hash,G(L)->strt.size,TString*);
+luaZ_freebuffer(L,&g->buff);
+freestack(L,L);
+(*g->frealloc)(g->ud,fromstate(L),state_size(LG),0);
+}
+static void luaE_freethread(lua_State*L,lua_State*L1){
+luaF_close(L1,L1->stack);
+freestack(L,L1);
+luaM_freemem(L,fromstate(L1),state_size(lua_State));
+}
+static lua_State*lua_newstate(lua_Alloc f,void*ud){
+int i;
+lua_State*L;
+global_State*g;
+void*l=(*f)(ud,NULL,0,state_size(LG));
+if(l==NULL)return NULL;
+L=tostate(l);
+g=&((LG*)L)->g;
+L->next=NULL;
+L->tt=8;
+g->currentwhite=bit2mask(0,5);
+L->marked=luaC_white(g);
+set2bits(L->marked,5,6);
+preinit_state(L,g);
+g->frealloc=f;
+g->ud=ud;
+g->mainthread=L;
+g->uvhead.u.l.prev=&g->uvhead;
+g->uvhead.u.l.next=&g->uvhead;
+g->GCthreshold=0;
+g->strt.size=0;
+g->strt.nuse=0;
+g->strt.hash=NULL;
+setnilvalue(registry(L));
+luaZ_initbuffer(L,&g->buff);
+g->panic=NULL;
+g->gcstate=0;
+g->rootgc=obj2gco(L);
+g->sweepstrgc=0;
+g->sweepgc=&g->rootgc;
+g->gray=NULL;
+g->grayagain=NULL;
+g->weak=NULL;
+g->tmudata=NULL;
+g->totalbytes=sizeof(LG);
+g->gcpause=200;
+g->gcstepmul=200;
+g->gcdept=0;
+for(i=0;i<(8+1);i++)g->mt[i]=NULL;
+if(luaD_rawrunprotected(L,f_luaopen,NULL)!=0){
+close_state(L);
+L=NULL;
+}
+else
+{}
+return L;
+}
+static void callallgcTM(lua_State*L,void*ud){
+UNUSED(ud);
+luaC_callGCTM(L);
+}
+static void lua_close(lua_State*L){
+L=G(L)->mainthread;
+luaF_close(L,L->stack);
+luaC_separateudata(L,1);
+L->errfunc=0;
+do{
+L->ci=L->base_ci;
+L->base=L->top=L->ci->base;
+L->nCcalls=L->baseCcalls=0;
+}while(luaD_rawrunprotected(L,callallgcTM,NULL)!=0);
+close_state(L);
+}
+#define getcode(fs,e)((fs)->f->code[(e)->u.s.info])
+#define luaK_codeAsBx(fs,o,A,sBx)luaK_codeABx(fs,o,A,(sBx)+(((1<<(9+9))-1)>>1))
+#define luaK_setmultret(fs,e)luaK_setreturns(fs,e,(-1))
+static int luaK_codeABx(FuncState*fs,OpCode o,int A,unsigned int Bx);
+static int luaK_codeABC(FuncState*fs,OpCode o,int A,int B,int C);
+static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults);
+static void luaK_patchtohere(FuncState*fs,int list);
+static void luaK_concat(FuncState*fs,int*l1,int l2);
+static int currentpc(lua_State*L,CallInfo*ci){
+if(!isLua(ci))return-1;
+if(ci==L->ci)
+ci->savedpc=L->savedpc;
+return pcRel(ci->savedpc,ci_func(ci)->l.p);
+}
+static int currentline(lua_State*L,CallInfo*ci){
+int pc=currentpc(L,ci);
+if(pc<0)
+return-1;
+else
+return getline_(ci_func(ci)->l.p,pc);
+}
+static int lua_getstack(lua_State*L,int level,lua_Debug*ar){
+int status;
+CallInfo*ci;
+for(ci=L->ci;level>0&&ci>L->base_ci;ci--){
+level--;
+if(f_isLua(ci))
+level-=ci->tailcalls;
+}
+if(level==0&&ci>L->base_ci){
+status=1;
+ar->i_ci=cast_int(ci-L->base_ci);
+}
+else if(level<0){
+status=1;
+ar->i_ci=0;
+}
+else status=0;
+return status;
+}
+static Proto*getluaproto(CallInfo*ci){
+return(isLua(ci)?ci_func(ci)->l.p:NULL);
+}
+static void funcinfo(lua_Debug*ar,Closure*cl){
+if(cl->c.isC){
+ar->source="=[C]";
+ar->linedefined=-1;
+ar->lastlinedefined=-1;
+ar->what="C";
+}
+else{
+ar->source=getstr(cl->l.p->source);
+ar->linedefined=cl->l.p->linedefined;
+ar->lastlinedefined=cl->l.p->lastlinedefined;
+ar->what=(ar->linedefined==0)?"main":"Lua";
+}
+luaO_chunkid(ar->short_src,ar->source,60);
+}
+static void info_tailcall(lua_Debug*ar){
+ar->name=ar->namewhat="";
+ar->what="tail";
+ar->lastlinedefined=ar->linedefined=ar->currentline=-1;
+ar->source="=(tail call)";
+luaO_chunkid(ar->short_src,ar->source,60);
+ar->nups=0;
+}
+static void collectvalidlines(lua_State*L,Closure*f){
+if(f==NULL||f->c.isC){
+setnilvalue(L->top);
+}
+else{
+Table*t=luaH_new(L,0,0);
+int*lineinfo=f->l.p->lineinfo;
+int i;
+for(i=0;i<f->l.p->sizelineinfo;i++)
+setbvalue(luaH_setnum(L,t,lineinfo[i]),1);
+sethvalue(L,L->top,t);
+}
+incr_top(L);
+}
+static int auxgetinfo(lua_State*L,const char*what,lua_Debug*ar,
+Closure*f,CallInfo*ci){
+int status=1;
+if(f==NULL){
+info_tailcall(ar);
+return status;
+}
+for(;*what;what++){
+switch(*what){
+case'S':{
+funcinfo(ar,f);
+break;
+}
+case'l':{
+ar->currentline=(ci)?currentline(L,ci):-1;
+break;
+}
+case'u':{
+ar->nups=f->c.nupvalues;
+break;
+}
+case'n':{
+ar->namewhat=(ci)?NULL:NULL;
+if(ar->namewhat==NULL){
+ar->namewhat="";
+ar->name=NULL;
+}
+break;
+}
+case'L':
+case'f':
+break;
+default:status=0;
+}
+}
+return status;
+}
+static int lua_getinfo(lua_State*L,const char*what,lua_Debug*ar){
+int status;
+Closure*f=NULL;
+CallInfo*ci=NULL;
+if(*what=='>'){
+StkId func=L->top-1;
+luai_apicheck(L,ttisfunction(func));
+what++;
+f=clvalue(func);
+L->top--;
+}
+else if(ar->i_ci!=0){
+ci=L->base_ci+ar->i_ci;
+f=clvalue(ci->func);
+}
+status=auxgetinfo(L,what,ar,f,ci);
+if(strchr(what,'f')){
+if(f==NULL)setnilvalue(L->top);
+else setclvalue(L,L->top,f);
+incr_top(L);
+}
+if(strchr(what,'L'))
+collectvalidlines(L,f);
+return status;
+}
+static int isinstack(CallInfo*ci,const TValue*o){
+StkId p;
+for(p=ci->base;p<ci->top;p++)
+if(o==p)return 1;
+return 0;
+}
+static void luaG_typeerror(lua_State*L,const TValue*o,const char*op){
+const char*name=NULL;
+const char*t=luaT_typenames[ttype(o)];
+const char*kind=(isinstack(L->ci,o))?
+NULL:
+NULL;
+if(kind)
+luaG_runerror(L,"attempt to %s %s "LUA_QL("%s")" (a %s value)",
+op,kind,name,t);
+else
+luaG_runerror(L,"attempt to %s a %s value",op,t);
+}
+static void luaG_concaterror(lua_State*L,StkId p1,StkId p2){
+if(ttisstring(p1)||ttisnumber(p1))p1=p2;
+luaG_typeerror(L,p1,"concatenate");
+}
+static void luaG_aritherror(lua_State*L,const TValue*p1,const TValue*p2){
+TValue temp;
+if(luaV_tonumber(p1,&temp)==NULL)
+p2=p1;
+luaG_typeerror(L,p2,"perform arithmetic on");
+}
+static int luaG_ordererror(lua_State*L,const TValue*p1,const TValue*p2){
+const char*t1=luaT_typenames[ttype(p1)];
+const char*t2=luaT_typenames[ttype(p2)];
+if(t1[2]==t2[2])
+luaG_runerror(L,"attempt to compare two %s values",t1);
+else
+luaG_runerror(L,"attempt to compare %s with %s",t1,t2);
+return 0;
+}
+static void addinfo(lua_State*L,const char*msg){
+CallInfo*ci=L->ci;
+if(isLua(ci)){
+char buff[60];
+int line=currentline(L,ci);
+luaO_chunkid(buff,getstr(getluaproto(ci)->source),60);
+luaO_pushfstring(L,"%s:%d: %s",buff,line,msg);
+}
+}
+static void luaG_errormsg(lua_State*L){
+if(L->errfunc!=0){
+StkId errfunc=restorestack(L,L->errfunc);
+if(!ttisfunction(errfunc))luaD_throw(L,5);
+setobj(L,L->top,L->top-1);
+setobj(L,L->top-1,errfunc);
+incr_top(L);
+luaD_call(L,L->top-2,1);
+}
+luaD_throw(L,2);
+}
+static void luaG_runerror(lua_State*L,const char*fmt,...){
+va_list argp;
+va_start(argp,fmt);
+addinfo(L,luaO_pushvfstring(L,fmt,argp));
+va_end(argp);
+luaG_errormsg(L);
+}
+static int luaZ_fill(ZIO*z){
+size_t size;
+lua_State*L=z->L;
+const char*buff;
+buff=z->reader(L,z->data,&size);
+if(buff==NULL||size==0)return(-1);
+z->n=size-1;
+z->p=buff;
+return char2int(*(z->p++));
+}
+static void luaZ_init(lua_State*L,ZIO*z,lua_Reader reader,void*data){
+z->L=L;
+z->reader=reader;
+z->data=data;
+z->n=0;
+z->p=NULL;
+}
+static char*luaZ_openspace(lua_State*L,Mbuffer*buff,size_t n){
+if(n>buff->buffsize){
+if(n<32)n=32;
+luaZ_resizebuffer(L,buff,n);
+}
+return buff->buffer;
+}
+#define opmode(t,a,b,c,m)(((t)<<7)|((a)<<6)|((b)<<4)|((c)<<2)|(m))
+static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)]={
+opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgK,OpArgN,iABx)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgU,OpArgN,iABC)
+,opmode(0,1,OpArgK,OpArgN,iABx)
+,opmode(0,1,OpArgR,OpArgK,iABC)
+,opmode(0,0,OpArgK,OpArgN,iABx)
+,opmode(0,0,OpArgU,OpArgN,iABC)
+,opmode(0,0,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,1,OpArgR,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgK,OpArgK,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgR,iABC)
+,opmode(0,0,OpArgR,OpArgN,iAsBx)
+,opmode(1,0,OpArgK,OpArgK,iABC)
+,opmode(1,0,OpArgK,OpArgK,iABC)
+,opmode(1,0,OpArgK,OpArgK,iABC)
+,opmode(1,1,OpArgR,OpArgU,iABC)
+,opmode(1,1,OpArgR,OpArgU,iABC)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,1,OpArgU,OpArgU,iABC)
+,opmode(0,0,OpArgU,OpArgN,iABC)
+,opmode(0,1,OpArgR,OpArgN,iAsBx)
+,opmode(0,1,OpArgR,OpArgN,iAsBx)
+,opmode(1,0,OpArgN,OpArgU,iABC)
+,opmode(0,0,OpArgU,OpArgU,iABC)
+,opmode(0,0,OpArgN,OpArgN,iABC)
+,opmode(0,1,OpArgU,OpArgN,iABx)
+,opmode(0,1,OpArgU,OpArgN,iABC)
+};
+#define next(ls)(ls->current=zgetc(ls->z))
+#define currIsNewline(ls)(ls->current=='\n'||ls->current=='\r')
+static const char*const luaX_tokens[]={
+"and","break","do","else","elseif",
+"end","false","for","function","if",
+"in","local","nil","not","or","repeat",
+"return","then","true","until","while",
+"..","...","==",">=","<=","~=",
+"<number>","<name>","<string>","<eof>",
+NULL
+};
+#define save_and_next(ls)(save(ls,ls->current),next(ls))
+static void save(LexState*ls,int c){
+Mbuffer*b=ls->buff;
+if(b->n+1>b->buffsize){
+size_t newsize;
+if(b->buffsize>=((size_t)(~(size_t)0)-2)/2)
+luaX_lexerror(ls,"lexical element too long",0);
+newsize=b->buffsize*2;
+luaZ_resizebuffer(ls->L,b,newsize);
+}
+b->buffer[b->n++]=cast(char,c);
+}
+static void luaX_init(lua_State*L){
+int i;
+for(i=0;i<(cast(int,TK_WHILE-257+1));i++){
+TString*ts=luaS_new(L,luaX_tokens[i]);
+luaS_fix(ts);
+ts->tsv.reserved=cast_byte(i+1);
+}
+}
+static const char*luaX_token2str(LexState*ls,int token){
+if(token<257){
+return(iscntrl(token))?luaO_pushfstring(ls->L,"char(%d)",token):
+luaO_pushfstring(ls->L,"%c",token);
+}
+else
+return luaX_tokens[token-257];
+}
+static const char*txtToken(LexState*ls,int token){
+switch(token){
+case TK_NAME:
+case TK_STRING:
+case TK_NUMBER:
+save(ls,'\0');
+return luaZ_buffer(ls->buff);
+default:
+return luaX_token2str(ls,token);
+}
+}
+static void luaX_lexerror(LexState*ls,const char*msg,int token){
+char buff[80];
+luaO_chunkid(buff,getstr(ls->source),80);
+msg=luaO_pushfstring(ls->L,"%s:%d: %s",buff,ls->linenumber,msg);
+if(token)
+luaO_pushfstring(ls->L,"%s near "LUA_QL("%s"),msg,txtToken(ls,token));
+luaD_throw(ls->L,3);
+}
+static void luaX_syntaxerror(LexState*ls,const char*msg){
+luaX_lexerror(ls,msg,ls->t.token);
+}
+static TString*luaX_newstring(LexState*ls,const char*str,size_t l){
+lua_State*L=ls->L;
+TString*ts=luaS_newlstr(L,str,l);
+TValue*o=luaH_setstr(L,ls->fs->h,ts);
+if(ttisnil(o)){
+setbvalue(o,1);
+luaC_checkGC(L);
+}
+return ts;
+}
+static void inclinenumber(LexState*ls){
+int old=ls->current;
+next(ls);
+if(currIsNewline(ls)&&ls->current!=old)
+next(ls);
+if(++ls->linenumber>=(INT_MAX-2))
+luaX_syntaxerror(ls,"chunk has too many lines");
+}
+static void luaX_setinput(lua_State*L,LexState*ls,ZIO*z,TString*source){
+ls->decpoint='.';
+ls->L=L;
+ls->lookahead.token=TK_EOS;
+ls->z=z;
+ls->fs=NULL;
+ls->linenumber=1;
+ls->lastline=1;
+ls->source=source;
+luaZ_resizebuffer(ls->L,ls->buff,32);
+next(ls);
+}
+static int check_next(LexState*ls,const char*set){
+if(!strchr(set,ls->current))
+return 0;
+save_and_next(ls);
+return 1;
+}
+static void buffreplace(LexState*ls,char from,char to){
+size_t n=luaZ_bufflen(ls->buff);
+char*p=luaZ_buffer(ls->buff);
+while(n--)
+if(p[n]==from)p[n]=to;
+}
+static void read_numeral(LexState*ls,SemInfo*seminfo){
+do{
+save_and_next(ls);
+}while(isdigit(ls->current)||ls->current=='.');
+if(check_next(ls,"Ee"))
+check_next(ls,"+-");
+while(isalnum(ls->current)||ls->current=='_')
+save_and_next(ls);
+save(ls,'\0');
+buffreplace(ls,'.',ls->decpoint);
+if(!luaO_str2d(luaZ_buffer(ls->buff),&seminfo->r))
+luaX_lexerror(ls,"malformed number",TK_NUMBER);
+}
+static int skip_sep(LexState*ls){
+int count=0;
+int s=ls->current;
+save_and_next(ls);
+while(ls->current=='='){
+save_and_next(ls);
+count++;
+}
+return(ls->current==s)?count:(-count)-1;
+}
+static void read_long_string(LexState*ls,SemInfo*seminfo,int sep){
+int cont=0;
+(void)(cont);
+save_and_next(ls);
+if(currIsNewline(ls))
+inclinenumber(ls);
+for(;;){
+switch(ls->current){
+case(-1):
+luaX_lexerror(ls,(seminfo)?"unfinished long string":
+"unfinished long comment",TK_EOS);
+break;
+case']':{
+if(skip_sep(ls)==sep){
+save_and_next(ls);
+goto endloop;
+}
+break;
+}
+case'\n':
+case'\r':{
+save(ls,'\n');
+inclinenumber(ls);
+if(!seminfo)luaZ_resetbuffer(ls->buff);
+break;
+}
+default:{
+if(seminfo)save_and_next(ls);
+else next(ls);
+}
+}
+}endloop:
+if(seminfo)
+seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+(2+sep),
+luaZ_bufflen(ls->buff)-2*(2+sep));
+}
+static void read_string(LexState*ls,int del,SemInfo*seminfo){
+save_and_next(ls);
+while(ls->current!=del){
+switch(ls->current){
+case(-1):
+luaX_lexerror(ls,"unfinished string",TK_EOS);
+continue;
+case'\n':
+case'\r':
+luaX_lexerror(ls,"unfinished string",TK_STRING);
+continue;
+case'\\':{
+int c;
+next(ls);
+switch(ls->current){
+case'a':c='\a';break;
+case'b':c='\b';break;
+case'f':c='\f';break;
+case'n':c='\n';break;
+case'r':c='\r';break;
+case't':c='\t';break;
+case'v':c='\v';break;
+case'\n':
+case'\r':save(ls,'\n');inclinenumber(ls);continue;
+case(-1):continue;
+default:{
+if(!isdigit(ls->current))
+save_and_next(ls);
+else{
+int i=0;
+c=0;
+do{
+c=10*c+(ls->current-'0');
+next(ls);
+}while(++i<3&&isdigit(ls->current));
+if(c>UCHAR_MAX)
+luaX_lexerror(ls,"escape sequence too large",TK_STRING);
+save(ls,c);
+}
+continue;
+}
+}
+save(ls,c);
+next(ls);
+continue;
+}
+default:
+save_and_next(ls);
+}
+}
+save_and_next(ls);
+seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+1,
+luaZ_bufflen(ls->buff)-2);
+}
+static int llex(LexState*ls,SemInfo*seminfo){
+luaZ_resetbuffer(ls->buff);
+for(;;){
+switch(ls->current){
+case'\n':
+case'\r':{
+inclinenumber(ls);
+continue;
+}
+case'-':{
+next(ls);
+if(ls->current!='-')return'-';
+next(ls);
+if(ls->current=='['){
+int sep=skip_sep(ls);
+luaZ_resetbuffer(ls->buff);
+if(sep>=0){
+read_long_string(ls,NULL,sep);
+luaZ_resetbuffer(ls->buff);
+continue;
+}
+}
+while(!currIsNewline(ls)&&ls->current!=(-1))
+next(ls);
+continue;
+}
+case'[':{
+int sep=skip_sep(ls);
+if(sep>=0){
+read_long_string(ls,seminfo,sep);
+return TK_STRING;
+}
+else if(sep==-1)return'[';
+else luaX_lexerror(ls,"invalid long string delimiter",TK_STRING);
+}
+case'=':{
+next(ls);
+if(ls->current!='=')return'=';
+else{next(ls);return TK_EQ;}
+}
+case'<':{
+next(ls);
+if(ls->current!='=')return'<';
+else{next(ls);return TK_LE;}
+}
+case'>':{
+next(ls);
+if(ls->current!='=')return'>';
+else{next(ls);return TK_GE;}
+}
+case'~':{
+next(ls);
+if(ls->current!='=')return'~';
+else{next(ls);return TK_NE;}
+}
+case'"':
+case'\'':{
+read_string(ls,ls->current,seminfo);
+return TK_STRING;
+}
+case'.':{
+save_and_next(ls);
+if(check_next(ls,".")){
+if(check_next(ls,"."))
+return TK_DOTS;
+else return TK_CONCAT;
+}
+else if(!isdigit(ls->current))return'.';
+else{
+read_numeral(ls,seminfo);
+return TK_NUMBER;
+}
+}
+case(-1):{
+return TK_EOS;
+}
+default:{
+if(isspace(ls->current)){
+next(ls);
+continue;
+}
+else if(isdigit(ls->current)){
+read_numeral(ls,seminfo);
+return TK_NUMBER;
+}
+else if(isalpha(ls->current)||ls->current=='_'){
+TString*ts;
+do{
+save_and_next(ls);
+}while(isalnum(ls->current)||ls->current=='_');
+ts=luaX_newstring(ls,luaZ_buffer(ls->buff),
+luaZ_bufflen(ls->buff));
+if(ts->tsv.reserved>0)
+return ts->tsv.reserved-1+257;
+else{
+seminfo->ts=ts;
+return TK_NAME;
+}
+}
+else{
+int c=ls->current;
+next(ls);
+return c;
+}
+}
+}
+}
+}
+static void luaX_next(LexState*ls){
+ls->lastline=ls->linenumber;
+if(ls->lookahead.token!=TK_EOS){
+ls->t=ls->lookahead;
+ls->lookahead.token=TK_EOS;
+}
+else
+ls->t.token=llex(ls,&ls->t.seminfo);
+}
+static void luaX_lookahead(LexState*ls){
+ls->lookahead.token=llex(ls,&ls->lookahead.seminfo);
+}
+#define hasjumps(e)((e)->t!=(e)->f)
+static int isnumeral(expdesc*e){
+return(e->k==VKNUM&&e->t==(-1)&&e->f==(-1));
+}
+static void luaK_nil(FuncState*fs,int from,int n){
+Instruction*previous;
+if(fs->pc>fs->lasttarget){
+if(fs->pc==0){
+if(from>=fs->nactvar)
+return;
+}
+else{
+previous=&fs->f->code[fs->pc-1];
+if(GET_OPCODE(*previous)==OP_LOADNIL){
+int pfrom=GETARG_A(*previous);
+int pto=GETARG_B(*previous);
+if(pfrom<=from&&from<=pto+1){
+if(from+n-1>pto)
+SETARG_B(*previous,from+n-1);
+return;
+}
+}
+}
+}
+luaK_codeABC(fs,OP_LOADNIL,from,from+n-1,0);
+}
+static int luaK_jump(FuncState*fs){
+int jpc=fs->jpc;
+int j;
+fs->jpc=(-1);
+j=luaK_codeAsBx(fs,OP_JMP,0,(-1));
+luaK_concat(fs,&j,jpc);
+return j;
+}
+static void luaK_ret(FuncState*fs,int first,int nret){
+luaK_codeABC(fs,OP_RETURN,first,nret+1,0);
+}
+static int condjump(FuncState*fs,OpCode op,int A,int B,int C){
+luaK_codeABC(fs,op,A,B,C);
+return luaK_jump(fs);
+}
+static void fixjump(FuncState*fs,int pc,int dest){
+Instruction*jmp=&fs->f->code[pc];
+int offset=dest-(pc+1);
+if(abs(offset)>(((1<<(9+9))-1)>>1))
+luaX_syntaxerror(fs->ls,"control structure too long");
+SETARG_sBx(*jmp,offset);
+}
+static int luaK_getlabel(FuncState*fs){
+fs->lasttarget=fs->pc;
+return fs->pc;
+}
+static int getjump(FuncState*fs,int pc){
+int offset=GETARG_sBx(fs->f->code[pc]);
+if(offset==(-1))
+return(-1);
+else
+return(pc+1)+offset;
+}
+static Instruction*getjumpcontrol(FuncState*fs,int pc){
+Instruction*pi=&fs->f->code[pc];
+if(pc>=1&&testTMode(GET_OPCODE(*(pi-1))))
+return pi-1;
+else
+return pi;
+}
+static int need_value(FuncState*fs,int list){
+for(;list!=(-1);list=getjump(fs,list)){
+Instruction i=*getjumpcontrol(fs,list);
+if(GET_OPCODE(i)!=OP_TESTSET)return 1;
+}
+return 0;
+}
+static int patchtestreg(FuncState*fs,int node,int reg){
+Instruction*i=getjumpcontrol(fs,node);
+if(GET_OPCODE(*i)!=OP_TESTSET)
+return 0;
+if(reg!=((1<<8)-1)&&reg!=GETARG_B(*i))
+SETARG_A(*i,reg);
+else
+*i=CREATE_ABC(OP_TEST,GETARG_B(*i),0,GETARG_C(*i));
+return 1;
+}
+static void removevalues(FuncState*fs,int list){
+for(;list!=(-1);list=getjump(fs,list))
+patchtestreg(fs,list,((1<<8)-1));
+}
+static void patchlistaux(FuncState*fs,int list,int vtarget,int reg,
+int dtarget){
+while(list!=(-1)){
+int next=getjump(fs,list);
+if(patchtestreg(fs,list,reg))
+fixjump(fs,list,vtarget);
+else
+fixjump(fs,list,dtarget);
+list=next;
+}
+}
+static void dischargejpc(FuncState*fs){
+patchlistaux(fs,fs->jpc,fs->pc,((1<<8)-1),fs->pc);
+fs->jpc=(-1);
+}
+static void luaK_patchlist(FuncState*fs,int list,int target){
+if(target==fs->pc)
+luaK_patchtohere(fs,list);
+else{
+patchlistaux(fs,list,target,((1<<8)-1),target);
+}
+}
+static void luaK_patchtohere(FuncState*fs,int list){
+luaK_getlabel(fs);
+luaK_concat(fs,&fs->jpc,list);
+}
+static void luaK_concat(FuncState*fs,int*l1,int l2){
+if(l2==(-1))return;
+else if(*l1==(-1))
+*l1=l2;
+else{
+int list=*l1;
+int next;
+while((next=getjump(fs,list))!=(-1))
+list=next;
+fixjump(fs,list,l2);
+}
+}
+static void luaK_checkstack(FuncState*fs,int n){
+int newstack=fs->freereg+n;
+if(newstack>fs->f->maxstacksize){
+if(newstack>=250)
+luaX_syntaxerror(fs->ls,"function or expression too complex");
+fs->f->maxstacksize=cast_byte(newstack);
+}
+}
+static void luaK_reserveregs(FuncState*fs,int n){
+luaK_checkstack(fs,n);
+fs->freereg+=n;
+}
+static void freereg(FuncState*fs,int reg){
+if(!ISK(reg)&&reg>=fs->nactvar){
+fs->freereg--;
+}
+}
+static void freeexp(FuncState*fs,expdesc*e){
+if(e->k==VNONRELOC)
+freereg(fs,e->u.s.info);
+}
+static int addk(FuncState*fs,TValue*k,TValue*v){
+lua_State*L=fs->L;
+TValue*idx=luaH_set(L,fs->h,k);
+Proto*f=fs->f;
+int oldsize=f->sizek;
+if(ttisnumber(idx)){
+return cast_int(nvalue(idx));
+}
+else{
+setnvalue(idx,cast_num(fs->nk));
+luaM_growvector(L,f->k,fs->nk,f->sizek,TValue,
+((1<<(9+9))-1),"constant table overflow");
+while(oldsize<f->sizek)setnilvalue(&f->k[oldsize++]);
+setobj(L,&f->k[fs->nk],v);
+luaC_barrier(L,f,v);
+return fs->nk++;
+}
+}
+static int luaK_stringK(FuncState*fs,TString*s){
+TValue o;
+setsvalue(fs->L,&o,s);
+return addk(fs,&o,&o);
+}
+static int luaK_numberK(FuncState*fs,lua_Number r){
+TValue o;
+setnvalue(&o,r);
+return addk(fs,&o,&o);
+}
+static int boolK(FuncState*fs,int b){
+TValue o;
+setbvalue(&o,b);
+return addk(fs,&o,&o);
+}
+static int nilK(FuncState*fs){
+TValue k,v;
+setnilvalue(&v);
+sethvalue(fs->L,&k,fs->h);
+return addk(fs,&k,&v);
+}
+static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults){
+if(e->k==VCALL){
+SETARG_C(getcode(fs,e),nresults+1);
+}
+else if(e->k==VVARARG){
+SETARG_B(getcode(fs,e),nresults+1);
+SETARG_A(getcode(fs,e),fs->freereg);
+luaK_reserveregs(fs,1);
+}
+}
+static void luaK_setoneret(FuncState*fs,expdesc*e){
+if(e->k==VCALL){
+e->k=VNONRELOC;
+e->u.s.info=GETARG_A(getcode(fs,e));
+}
+else if(e->k==VVARARG){
+SETARG_B(getcode(fs,e),2);
+e->k=VRELOCABLE;
+}
+}
+static void luaK_dischargevars(FuncState*fs,expdesc*e){
+switch(e->k){
+case VLOCAL:{
+e->k=VNONRELOC;
+break;
+}
+case VUPVAL:{
+e->u.s.info=luaK_codeABC(fs,OP_GETUPVAL,0,e->u.s.info,0);
+e->k=VRELOCABLE;
+break;
+}
+case VGLOBAL:{
+e->u.s.info=luaK_codeABx(fs,OP_GETGLOBAL,0,e->u.s.info);
+e->k=VRELOCABLE;
+break;
+}
+case VINDEXED:{
+freereg(fs,e->u.s.aux);
+freereg(fs,e->u.s.info);
+e->u.s.info=luaK_codeABC(fs,OP_GETTABLE,0,e->u.s.info,e->u.s.aux);
+e->k=VRELOCABLE;
+break;
+}
+case VVARARG:
+case VCALL:{
+luaK_setoneret(fs,e);
+break;
+}
+default:break;
+}
+}
+static int code_label(FuncState*fs,int A,int b,int jump){
+luaK_getlabel(fs);
+return luaK_codeABC(fs,OP_LOADBOOL,A,b,jump);
+}
+static void discharge2reg(FuncState*fs,expdesc*e,int reg){
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VNIL:{
+luaK_nil(fs,reg,1);
+break;
+}
+case VFALSE:case VTRUE:{
+luaK_codeABC(fs,OP_LOADBOOL,reg,e->k==VTRUE,0);
+break;
+}
+case VK:{
+luaK_codeABx(fs,OP_LOADK,reg,e->u.s.info);
+break;
+}
+case VKNUM:{
+luaK_codeABx(fs,OP_LOADK,reg,luaK_numberK(fs,e->u.nval));
+break;
+}
+case VRELOCABLE:{
+Instruction*pc=&getcode(fs,e);
+SETARG_A(*pc,reg);
+break;
+}
+case VNONRELOC:{
+if(reg!=e->u.s.info)
+luaK_codeABC(fs,OP_MOVE,reg,e->u.s.info,0);
+break;
+}
+default:{
+return;
+}
+}
+e->u.s.info=reg;
+e->k=VNONRELOC;
+}
+static void discharge2anyreg(FuncState*fs,expdesc*e){
+if(e->k!=VNONRELOC){
+luaK_reserveregs(fs,1);
+discharge2reg(fs,e,fs->freereg-1);
+}
+}
+static void exp2reg(FuncState*fs,expdesc*e,int reg){
+discharge2reg(fs,e,reg);
+if(e->k==VJMP)
+luaK_concat(fs,&e->t,e->u.s.info);
+if(hasjumps(e)){
+int final;
+int p_f=(-1);
+int p_t=(-1);
+if(need_value(fs,e->t)||need_value(fs,e->f)){
+int fj=(e->k==VJMP)?(-1):luaK_jump(fs);
+p_f=code_label(fs,reg,0,1);
+p_t=code_label(fs,reg,1,0);
+luaK_patchtohere(fs,fj);
+}
+final=luaK_getlabel(fs);
+patchlistaux(fs,e->f,final,reg,p_f);
+patchlistaux(fs,e->t,final,reg,p_t);
+}
+e->f=e->t=(-1);
+e->u.s.info=reg;
+e->k=VNONRELOC;
+}
+static void luaK_exp2nextreg(FuncState*fs,expdesc*e){
+luaK_dischargevars(fs,e);
+freeexp(fs,e);
+luaK_reserveregs(fs,1);
+exp2reg(fs,e,fs->freereg-1);
+}
+static int luaK_exp2anyreg(FuncState*fs,expdesc*e){
+luaK_dischargevars(fs,e);
+if(e->k==VNONRELOC){
+if(!hasjumps(e))return e->u.s.info;
+if(e->u.s.info>=fs->nactvar){
+exp2reg(fs,e,e->u.s.info);
+return e->u.s.info;
+}
+}
+luaK_exp2nextreg(fs,e);
+return e->u.s.info;
+}
+static void luaK_exp2val(FuncState*fs,expdesc*e){
+if(hasjumps(e))
+luaK_exp2anyreg(fs,e);
+else
+luaK_dischargevars(fs,e);
+}
+static int luaK_exp2RK(FuncState*fs,expdesc*e){
+luaK_exp2val(fs,e);
+switch(e->k){
+case VKNUM:
+case VTRUE:
+case VFALSE:
+case VNIL:{
+if(fs->nk<=((1<<(9-1))-1)){
+e->u.s.info=(e->k==VNIL)?nilK(fs):
+(e->k==VKNUM)?luaK_numberK(fs,e->u.nval):
+boolK(fs,(e->k==VTRUE));
+e->k=VK;
+return RKASK(e->u.s.info);
+}
+else break;
+}
+case VK:{
+if(e->u.s.info<=((1<<(9-1))-1))
+return RKASK(e->u.s.info);
+else break;
+}
+default:break;
+}
+return luaK_exp2anyreg(fs,e);
+}
+static void luaK_storevar(FuncState*fs,expdesc*var,expdesc*ex){
+switch(var->k){
+case VLOCAL:{
+freeexp(fs,ex);
+exp2reg(fs,ex,var->u.s.info);
+return;
+}
+case VUPVAL:{
+int e=luaK_exp2anyreg(fs,ex);
+luaK_codeABC(fs,OP_SETUPVAL,e,var->u.s.info,0);
+break;
+}
+case VGLOBAL:{
+int e=luaK_exp2anyreg(fs,ex);
+luaK_codeABx(fs,OP_SETGLOBAL,e,var->u.s.info);
+break;
+}
+case VINDEXED:{
+int e=luaK_exp2RK(fs,ex);
+luaK_codeABC(fs,OP_SETTABLE,var->u.s.info,var->u.s.aux,e);
+break;
+}
+default:{
+break;
+}
+}
+freeexp(fs,ex);
+}
+static void luaK_self(FuncState*fs,expdesc*e,expdesc*key){
+int func;
+luaK_exp2anyreg(fs,e);
+freeexp(fs,e);
+func=fs->freereg;
+luaK_reserveregs(fs,2);
+luaK_codeABC(fs,OP_SELF,func,e->u.s.info,luaK_exp2RK(fs,key));
+freeexp(fs,key);
+e->u.s.info=func;
+e->k=VNONRELOC;
+}
+static void invertjump(FuncState*fs,expdesc*e){
+Instruction*pc=getjumpcontrol(fs,e->u.s.info);
+SETARG_A(*pc,!(GETARG_A(*pc)));
+}
+static int jumponcond(FuncState*fs,expdesc*e,int cond){
+if(e->k==VRELOCABLE){
+Instruction ie=getcode(fs,e);
+if(GET_OPCODE(ie)==OP_NOT){
+fs->pc--;
+return condjump(fs,OP_TEST,GETARG_B(ie),0,!cond);
+}
+}
+discharge2anyreg(fs,e);
+freeexp(fs,e);
+return condjump(fs,OP_TESTSET,((1<<8)-1),e->u.s.info,cond);
+}
+static void luaK_goiftrue(FuncState*fs,expdesc*e){
+int pc;
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VK:case VKNUM:case VTRUE:{
+pc=(-1);
+break;
+}
+case VJMP:{
+invertjump(fs,e);
+pc=e->u.s.info;
+break;
+}
+default:{
+pc=jumponcond(fs,e,0);
+break;
+}
+}
+luaK_concat(fs,&e->f,pc);
+luaK_patchtohere(fs,e->t);
+e->t=(-1);
+}
+static void luaK_goiffalse(FuncState*fs,expdesc*e){
+int pc;
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VNIL:case VFALSE:{
+pc=(-1);
+break;
+}
+case VJMP:{
+pc=e->u.s.info;
+break;
+}
+default:{
+pc=jumponcond(fs,e,1);
+break;
+}
+}
+luaK_concat(fs,&e->t,pc);
+luaK_patchtohere(fs,e->f);
+e->f=(-1);
+}
+static void codenot(FuncState*fs,expdesc*e){
+luaK_dischargevars(fs,e);
+switch(e->k){
+case VNIL:case VFALSE:{
+e->k=VTRUE;
+break;
+}
+case VK:case VKNUM:case VTRUE:{
+e->k=VFALSE;
+break;
+}
+case VJMP:{
+invertjump(fs,e);
+break;
+}
+case VRELOCABLE:
+case VNONRELOC:{
+discharge2anyreg(fs,e);
+freeexp(fs,e);
+e->u.s.info=luaK_codeABC(fs,OP_NOT,0,e->u.s.info,0);
+e->k=VRELOCABLE;
+break;
+}
+default:{
+break;
+}
+}
+{int temp=e->f;e->f=e->t;e->t=temp;}
+removevalues(fs,e->f);
+removevalues(fs,e->t);
+}
+static void luaK_indexed(FuncState*fs,expdesc*t,expdesc*k){
+t->u.s.aux=luaK_exp2RK(fs,k);
+t->k=VINDEXED;
+}
+static int constfolding(OpCode op,expdesc*e1,expdesc*e2){
+lua_Number v1,v2,r;
+if(!isnumeral(e1)||!isnumeral(e2))return 0;
+v1=e1->u.nval;
+v2=e2->u.nval;
+switch(op){
+case OP_ADD:r=luai_numadd(v1,v2);break;
+case OP_SUB:r=luai_numsub(v1,v2);break;
+case OP_MUL:r=luai_nummul(v1,v2);break;
+case OP_DIV:
+if(v2==0)return 0;
+r=luai_numdiv(v1,v2);break;
+case OP_MOD:
+if(v2==0)return 0;
+r=luai_nummod(v1,v2);break;
+case OP_POW:r=luai_numpow(v1,v2);break;
+case OP_UNM:r=luai_numunm(v1);break;
+case OP_LEN:return 0;
+default:r=0;break;
+}
+if(luai_numisnan(r))return 0;
+e1->u.nval=r;
+return 1;
+}
+static void codearith(FuncState*fs,OpCode op,expdesc*e1,expdesc*e2){
+if(constfolding(op,e1,e2))
+return;
+else{
+int o2=(op!=OP_UNM&&op!=OP_LEN)?luaK_exp2RK(fs,e2):0;
+int o1=luaK_exp2RK(fs,e1);
+if(o1>o2){
+freeexp(fs,e1);
+freeexp(fs,e2);
+}
+else{
+freeexp(fs,e2);
+freeexp(fs,e1);
+}
+e1->u.s.info=luaK_codeABC(fs,op,0,o1,o2);
+e1->k=VRELOCABLE;
+}
+}
+static void codecomp(FuncState*fs,OpCode op,int cond,expdesc*e1,
+expdesc*e2){
+int o1=luaK_exp2RK(fs,e1);
+int o2=luaK_exp2RK(fs,e2);
+freeexp(fs,e2);
+freeexp(fs,e1);
+if(cond==0&&op!=OP_EQ){
+int temp;
+temp=o1;o1=o2;o2=temp;
+cond=1;
+}
+e1->u.s.info=condjump(fs,op,cond,o1,o2);
+e1->k=VJMP;
+}
+static void luaK_prefix(FuncState*fs,UnOpr op,expdesc*e){
+expdesc e2;
+e2.t=e2.f=(-1);e2.k=VKNUM;e2.u.nval=0;
+switch(op){
+case OPR_MINUS:{
+if(!isnumeral(e))
+luaK_exp2anyreg(fs,e);
+codearith(fs,OP_UNM,e,&e2);
+break;
+}
+case OPR_NOT:codenot(fs,e);break;
+case OPR_LEN:{
+luaK_exp2anyreg(fs,e);
+codearith(fs,OP_LEN,e,&e2);
+break;
+}
+default:;
+}
+}
+static void luaK_infix(FuncState*fs,BinOpr op,expdesc*v){
+switch(op){
+case OPR_AND:{
+luaK_goiftrue(fs,v);
+break;
+}
+case OPR_OR:{
+luaK_goiffalse(fs,v);
+break;
+}
+case OPR_CONCAT:{
+luaK_exp2nextreg(fs,v);
+break;
+}
+case OPR_ADD:case OPR_SUB:case OPR_MUL:case OPR_DIV:
+case OPR_MOD:case OPR_POW:{
+if(!isnumeral(v))luaK_exp2RK(fs,v);
+break;
+}
+default:{
+luaK_exp2RK(fs,v);
+break;
+}
+}
+}
+static void luaK_posfix(FuncState*fs,BinOpr op,expdesc*e1,expdesc*e2){
+switch(op){
+case OPR_AND:{
+luaK_dischargevars(fs,e2);
+luaK_concat(fs,&e2->f,e1->f);
+*e1=*e2;
+break;
+}
+case OPR_OR:{
+luaK_dischargevars(fs,e2);
+luaK_concat(fs,&e2->t,e1->t);
+*e1=*e2;
+break;
+}
+case OPR_CONCAT:{
+luaK_exp2val(fs,e2);
+if(e2->k==VRELOCABLE&&GET_OPCODE(getcode(fs,e2))==OP_CONCAT){
+freeexp(fs,e1);
+SETARG_B(getcode(fs,e2),e1->u.s.info);
+e1->k=VRELOCABLE;e1->u.s.info=e2->u.s.info;
+}
+else{
+luaK_exp2nextreg(fs,e2);
+codearith(fs,OP_CONCAT,e1,e2);
+}
+break;
+}
+case OPR_ADD:codearith(fs,OP_ADD,e1,e2);break;
+case OPR_SUB:codearith(fs,OP_SUB,e1,e2);break;
+case OPR_MUL:codearith(fs,OP_MUL,e1,e2);break;
+case OPR_DIV:codearith(fs,OP_DIV,e1,e2);break;
+case OPR_MOD:codearith(fs,OP_MOD,e1,e2);break;
+case OPR_POW:codearith(fs,OP_POW,e1,e2);break;
+case OPR_EQ:codecomp(fs,OP_EQ,1,e1,e2);break;
+case OPR_NE:codecomp(fs,OP_EQ,0,e1,e2);break;
+case OPR_LT:codecomp(fs,OP_LT,1,e1,e2);break;
+case OPR_LE:codecomp(fs,OP_LE,1,e1,e2);break;
+case OPR_GT:codecomp(fs,OP_LT,0,e1,e2);break;
+case OPR_GE:codecomp(fs,OP_LE,0,e1,e2);break;
+default:;
+}
+}
+static void luaK_fixline(FuncState*fs,int line){
+fs->f->lineinfo[fs->pc-1]=line;
+}
+static int luaK_code(FuncState*fs,Instruction i,int line){
+Proto*f=fs->f;
+dischargejpc(fs);
+luaM_growvector(fs->L,f->code,fs->pc,f->sizecode,Instruction,
+(INT_MAX-2),"code size overflow");
+f->code[fs->pc]=i;
+luaM_growvector(fs->L,f->lineinfo,fs->pc,f->sizelineinfo,int,
+(INT_MAX-2),"code size overflow");
+f->lineinfo[fs->pc]=line;
+return fs->pc++;
+}
+static int luaK_codeABC(FuncState*fs,OpCode o,int a,int b,int c){
+return luaK_code(fs,CREATE_ABC(o,a,b,c),fs->ls->lastline);
+}
+static int luaK_codeABx(FuncState*fs,OpCode o,int a,unsigned int bc){
+return luaK_code(fs,CREATE_ABx(o,a,bc),fs->ls->lastline);
+}
+static void luaK_setlist(FuncState*fs,int base,int nelems,int tostore){
+int c=(nelems-1)/50+1;
+int b=(tostore==(-1))?0:tostore;
+if(c<=((1<<9)-1))
+luaK_codeABC(fs,OP_SETLIST,base,b,c);
+else{
+luaK_codeABC(fs,OP_SETLIST,base,b,0);
+luaK_code(fs,cast(Instruction,c),fs->ls->lastline);
+}
+fs->freereg=base+1;
+}
+#define hasmultret(k)((k)==VCALL||(k)==VVARARG)
+#define getlocvar(fs,i)((fs)->f->locvars[(fs)->actvar[i]])
+#define luaY_checklimit(fs,v,l,m)if((v)>(l))errorlimit(fs,l,m)
+typedef struct BlockCnt{
+struct BlockCnt*previous;
+int breaklist;
+lu_byte nactvar;
+lu_byte upval;
+lu_byte isbreakable;
+}BlockCnt;
+static void chunk(LexState*ls);
+static void expr(LexState*ls,expdesc*v);
+static void anchor_token(LexState*ls){
+if(ls->t.token==TK_NAME||ls->t.token==TK_STRING){
+TString*ts=ls->t.seminfo.ts;
+luaX_newstring(ls,getstr(ts),ts->tsv.len);
+}
+}
+static void error_expected(LexState*ls,int token){
+luaX_syntaxerror(ls,
+luaO_pushfstring(ls->L,LUA_QL("%s")" expected",luaX_token2str(ls,token)));
+}
+static void errorlimit(FuncState*fs,int limit,const char*what){
+const char*msg=(fs->f->linedefined==0)?
+luaO_pushfstring(fs->L,"main function has more than %d %s",limit,what):
+luaO_pushfstring(fs->L,"function at line %d has more than %d %s",
+fs->f->linedefined,limit,what);
+luaX_lexerror(fs->ls,msg,0);
+}
+static int testnext(LexState*ls,int c){
+if(ls->t.token==c){
+luaX_next(ls);
+return 1;
+}
+else return 0;
+}
+static void check(LexState*ls,int c){
+if(ls->t.token!=c)
+error_expected(ls,c);
+}
+static void checknext(LexState*ls,int c){
+check(ls,c);
+luaX_next(ls);
+}
+#define check_condition(ls,c,msg){if(!(c))luaX_syntaxerror(ls,msg);}
+static void check_match(LexState*ls,int what,int who,int where){
+if(!testnext(ls,what)){
+if(where==ls->linenumber)
+error_expected(ls,what);
+else{
+luaX_syntaxerror(ls,luaO_pushfstring(ls->L,
+LUA_QL("%s")" expected (to close "LUA_QL("%s")" at line %d)",
+luaX_token2str(ls,what),luaX_token2str(ls,who),where));
+}
+}
+}
+static TString*str_checkname(LexState*ls){
+TString*ts;
+check(ls,TK_NAME);
+ts=ls->t.seminfo.ts;
+luaX_next(ls);
+return ts;
+}
+static void init_exp(expdesc*e,expkind k,int i){
+e->f=e->t=(-1);
+e->k=k;
+e->u.s.info=i;
+}
+static void codestring(LexState*ls,expdesc*e,TString*s){
+init_exp(e,VK,luaK_stringK(ls->fs,s));
+}
+static void checkname(LexState*ls,expdesc*e){
+codestring(ls,e,str_checkname(ls));
+}
+static int registerlocalvar(LexState*ls,TString*varname){
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+int oldsize=f->sizelocvars;
+luaM_growvector(ls->L,f->locvars,fs->nlocvars,f->sizelocvars,
+LocVar,SHRT_MAX,"too many local variables");
+while(oldsize<f->sizelocvars)f->locvars[oldsize++].varname=NULL;
+f->locvars[fs->nlocvars].varname=varname;
+luaC_objbarrier(ls->L,f,varname);
+return fs->nlocvars++;
+}
+#define new_localvarliteral(ls,v,n)new_localvar(ls,luaX_newstring(ls,""v,(sizeof(v)/sizeof(char))-1),n)
+static void new_localvar(LexState*ls,TString*name,int n){
+FuncState*fs=ls->fs;
+luaY_checklimit(fs,fs->nactvar+n+1,200,"local variables");
+fs->actvar[fs->nactvar+n]=cast(unsigned short,registerlocalvar(ls,name));
+}
+static void adjustlocalvars(LexState*ls,int nvars){
+FuncState*fs=ls->fs;
+fs->nactvar=cast_byte(fs->nactvar+nvars);
+for(;nvars;nvars--){
+getlocvar(fs,fs->nactvar-nvars).startpc=fs->pc;
+}
+}
+static void removevars(LexState*ls,int tolevel){
+FuncState*fs=ls->fs;
+while(fs->nactvar>tolevel)
+getlocvar(fs,--fs->nactvar).endpc=fs->pc;
+}
+static int indexupvalue(FuncState*fs,TString*name,expdesc*v){
+int i;
+Proto*f=fs->f;
+int oldsize=f->sizeupvalues;
+for(i=0;i<f->nups;i++){
+if(fs->upvalues[i].k==v->k&&fs->upvalues[i].info==v->u.s.info){
+return i;
+}
+}
+luaY_checklimit(fs,f->nups+1,60,"upvalues");
+luaM_growvector(fs->L,f->upvalues,f->nups,f->sizeupvalues,
+TString*,(INT_MAX-2),"");
+while(oldsize<f->sizeupvalues)f->upvalues[oldsize++]=NULL;
+f->upvalues[f->nups]=name;
+luaC_objbarrier(fs->L,f,name);
+fs->upvalues[f->nups].k=cast_byte(v->k);
+fs->upvalues[f->nups].info=cast_byte(v->u.s.info);
+return f->nups++;
+}
+static int searchvar(FuncState*fs,TString*n){
+int i;
+for(i=fs->nactvar-1;i>=0;i--){
+if(n==getlocvar(fs,i).varname)
+return i;
+}
+return-1;
+}
+static void markupval(FuncState*fs,int level){
+BlockCnt*bl=fs->bl;
+while(bl&&bl->nactvar>level)bl=bl->previous;
+if(bl)bl->upval=1;
+}
+static int singlevaraux(FuncState*fs,TString*n,expdesc*var,int base){
+if(fs==NULL){
+init_exp(var,VGLOBAL,((1<<8)-1));
+return VGLOBAL;
+}
+else{
+int v=searchvar(fs,n);
+if(v>=0){
+init_exp(var,VLOCAL,v);
+if(!base)
+markupval(fs,v);
+return VLOCAL;
+}
+else{
+if(singlevaraux(fs->prev,n,var,0)==VGLOBAL)
+return VGLOBAL;
+var->u.s.info=indexupvalue(fs,n,var);
+var->k=VUPVAL;
+return VUPVAL;
+}
+}
+}
+static void singlevar(LexState*ls,expdesc*var){
+TString*varname=str_checkname(ls);
+FuncState*fs=ls->fs;
+if(singlevaraux(fs,varname,var,1)==VGLOBAL)
+var->u.s.info=luaK_stringK(fs,varname);
+}
+static void adjust_assign(LexState*ls,int nvars,int nexps,expdesc*e){
+FuncState*fs=ls->fs;
+int extra=nvars-nexps;
+if(hasmultret(e->k)){
+extra++;
+if(extra<0)extra=0;
+luaK_setreturns(fs,e,extra);
+if(extra>1)luaK_reserveregs(fs,extra-1);
+}
+else{
+if(e->k!=VVOID)luaK_exp2nextreg(fs,e);
+if(extra>0){
+int reg=fs->freereg;
+luaK_reserveregs(fs,extra);
+luaK_nil(fs,reg,extra);
+}
+}
+}
+static void enterlevel(LexState*ls){
+if(++ls->L->nCcalls>200)
+luaX_lexerror(ls,"chunk has too many syntax levels",0);
+}
+#define leavelevel(ls)((ls)->L->nCcalls--)
+static void enterblock(FuncState*fs,BlockCnt*bl,lu_byte isbreakable){
+bl->breaklist=(-1);
+bl->isbreakable=isbreakable;
+bl->nactvar=fs->nactvar;
+bl->upval=0;
+bl->previous=fs->bl;
+fs->bl=bl;
+}
+static void leaveblock(FuncState*fs){
+BlockCnt*bl=fs->bl;
+fs->bl=bl->previous;
+removevars(fs->ls,bl->nactvar);
+if(bl->upval)
+luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0);
+fs->freereg=fs->nactvar;
+luaK_patchtohere(fs,bl->breaklist);
+}
+static void pushclosure(LexState*ls,FuncState*func,expdesc*v){
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+int oldsize=f->sizep;
+int i;
+luaM_growvector(ls->L,f->p,fs->np,f->sizep,Proto*,
+((1<<(9+9))-1),"constant table overflow");
+while(oldsize<f->sizep)f->p[oldsize++]=NULL;
+f->p[fs->np++]=func->f;
+luaC_objbarrier(ls->L,f,func->f);
+init_exp(v,VRELOCABLE,luaK_codeABx(fs,OP_CLOSURE,0,fs->np-1));
+for(i=0;i<func->f->nups;i++){
+OpCode o=(func->upvalues[i].k==VLOCAL)?OP_MOVE:OP_GETUPVAL;
+luaK_codeABC(fs,o,0,func->upvalues[i].info,0);
+}
+}
+static void open_func(LexState*ls,FuncState*fs){
+lua_State*L=ls->L;
+Proto*f=luaF_newproto(L);
+fs->f=f;
+fs->prev=ls->fs;
+fs->ls=ls;
+fs->L=L;
+ls->fs=fs;
+fs->pc=0;
+fs->lasttarget=-1;
+fs->jpc=(-1);
+fs->freereg=0;
+fs->nk=0;
+fs->np=0;
+fs->nlocvars=0;
+fs->nactvar=0;
+fs->bl=NULL;
+f->source=ls->source;
+f->maxstacksize=2;
+fs->h=luaH_new(L,0,0);
+sethvalue(L,L->top,fs->h);
+incr_top(L);
+setptvalue(L,L->top,f);
+incr_top(L);
+}
+static void close_func(LexState*ls){
+lua_State*L=ls->L;
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+removevars(ls,0);
+luaK_ret(fs,0,0);
+luaM_reallocvector(L,f->code,f->sizecode,fs->pc,Instruction);
+f->sizecode=fs->pc;
+luaM_reallocvector(L,f->lineinfo,f->sizelineinfo,fs->pc,int);
+f->sizelineinfo=fs->pc;
+luaM_reallocvector(L,f->k,f->sizek,fs->nk,TValue);
+f->sizek=fs->nk;
+luaM_reallocvector(L,f->p,f->sizep,fs->np,Proto*);
+f->sizep=fs->np;
+luaM_reallocvector(L,f->locvars,f->sizelocvars,fs->nlocvars,LocVar);
+f->sizelocvars=fs->nlocvars;
+luaM_reallocvector(L,f->upvalues,f->sizeupvalues,f->nups,TString*);
+f->sizeupvalues=f->nups;
+ls->fs=fs->prev;
+if(fs)anchor_token(ls);
+L->top-=2;
+}
+static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff,const char*name){
+struct LexState lexstate;
+struct FuncState funcstate;
+lexstate.buff=buff;
+luaX_setinput(L,&lexstate,z,luaS_new(L,name));
+open_func(&lexstate,&funcstate);
+funcstate.f->is_vararg=2;
+luaX_next(&lexstate);
+chunk(&lexstate);
+check(&lexstate,TK_EOS);
+close_func(&lexstate);
+return funcstate.f;
+}
+static void field(LexState*ls,expdesc*v){
+FuncState*fs=ls->fs;
+expdesc key;
+luaK_exp2anyreg(fs,v);
+luaX_next(ls);
+checkname(ls,&key);
+luaK_indexed(fs,v,&key);
+}
+static void yindex(LexState*ls,expdesc*v){
+luaX_next(ls);
+expr(ls,v);
+luaK_exp2val(ls->fs,v);
+checknext(ls,']');
+}
+struct ConsControl{
+expdesc v;
+expdesc*t;
+int nh;
+int na;
+int tostore;
+};
+static void recfield(LexState*ls,struct ConsControl*cc){
+FuncState*fs=ls->fs;
+int reg=ls->fs->freereg;
+expdesc key,val;
+int rkkey;
+if(ls->t.token==TK_NAME){
+luaY_checklimit(fs,cc->nh,(INT_MAX-2),"items in a constructor");
+checkname(ls,&key);
+}
+else
+yindex(ls,&key);
+cc->nh++;
+checknext(ls,'=');
+rkkey=luaK_exp2RK(fs,&key);
+expr(ls,&val);
+luaK_codeABC(fs,OP_SETTABLE,cc->t->u.s.info,rkkey,luaK_exp2RK(fs,&val));
+fs->freereg=reg;
+}
+static void closelistfield(FuncState*fs,struct ConsControl*cc){
+if(cc->v.k==VVOID)return;
+luaK_exp2nextreg(fs,&cc->v);
+cc->v.k=VVOID;
+if(cc->tostore==50){
+luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore);
+cc->tostore=0;
+}
+}
+static void lastlistfield(FuncState*fs,struct ConsControl*cc){
+if(cc->tostore==0)return;
+if(hasmultret(cc->v.k)){
+luaK_setmultret(fs,&cc->v);
+luaK_setlist(fs,cc->t->u.s.info,cc->na,(-1));
+cc->na--;
+}
+else{
+if(cc->v.k!=VVOID)
+luaK_exp2nextreg(fs,&cc->v);
+luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore);
+}
+}
+static void listfield(LexState*ls,struct ConsControl*cc){
+expr(ls,&cc->v);
+luaY_checklimit(ls->fs,cc->na,(INT_MAX-2),"items in a constructor");
+cc->na++;
+cc->tostore++;
+}
+static void constructor(LexState*ls,expdesc*t){
+FuncState*fs=ls->fs;
+int line=ls->linenumber;
+int pc=luaK_codeABC(fs,OP_NEWTABLE,0,0,0);
+struct ConsControl cc;
+cc.na=cc.nh=cc.tostore=0;
+cc.t=t;
+init_exp(t,VRELOCABLE,pc);
+init_exp(&cc.v,VVOID,0);
+luaK_exp2nextreg(ls->fs,t);
+checknext(ls,'{');
+do{
+if(ls->t.token=='}')break;
+closelistfield(fs,&cc);
+switch(ls->t.token){
+case TK_NAME:{
+luaX_lookahead(ls);
+if(ls->lookahead.token!='=')
+listfield(ls,&cc);
+else
+recfield(ls,&cc);
+break;
+}
+case'[':{
+recfield(ls,&cc);
+break;
+}
+default:{
+listfield(ls,&cc);
+break;
+}
+}
+}while(testnext(ls,',')||testnext(ls,';'));
+check_match(ls,'}','{',line);
+lastlistfield(fs,&cc);
+SETARG_B(fs->f->code[pc],luaO_int2fb(cc.na));
+SETARG_C(fs->f->code[pc],luaO_int2fb(cc.nh));
+}
+static void parlist(LexState*ls){
+FuncState*fs=ls->fs;
+Proto*f=fs->f;
+int nparams=0;
+f->is_vararg=0;
+if(ls->t.token!=')'){
+do{
+switch(ls->t.token){
+case TK_NAME:{
+new_localvar(ls,str_checkname(ls),nparams++);
+break;
+}
+case TK_DOTS:{
+luaX_next(ls);
+f->is_vararg|=2;
+break;
+}
+default:luaX_syntaxerror(ls,"<name> or "LUA_QL("...")" expected");
+}
+}while(!f->is_vararg&&testnext(ls,','));
+}
+adjustlocalvars(ls,nparams);
+f->numparams=cast_byte(fs->nactvar-(f->is_vararg&1));
+luaK_reserveregs(fs,fs->nactvar);
+}
+static void body(LexState*ls,expdesc*e,int needself,int line){
+FuncState new_fs;
+open_func(ls,&new_fs);
+new_fs.f->linedefined=line;
+checknext(ls,'(');
+if(needself){
+new_localvarliteral(ls,"self",0);
+adjustlocalvars(ls,1);
+}
+parlist(ls);
+checknext(ls,')');
+chunk(ls);
+new_fs.f->lastlinedefined=ls->linenumber;
+check_match(ls,TK_END,TK_FUNCTION,line);
+close_func(ls);
+pushclosure(ls,&new_fs,e);
+}
+static int explist1(LexState*ls,expdesc*v){
+int n=1;
+expr(ls,v);
+while(testnext(ls,',')){
+luaK_exp2nextreg(ls->fs,v);
+expr(ls,v);
+n++;
+}
+return n;
+}
+static void funcargs(LexState*ls,expdesc*f){
+FuncState*fs=ls->fs;
+expdesc args;
+int base,nparams;
+int line=ls->linenumber;
+switch(ls->t.token){
+case'(':{
+if(line!=ls->lastline)
+luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)");
+luaX_next(ls);
+if(ls->t.token==')')
+args.k=VVOID;
+else{
+explist1(ls,&args);
+luaK_setmultret(fs,&args);
+}
+check_match(ls,')','(',line);
+break;
+}
+case'{':{
+constructor(ls,&args);
+break;
+}
+case TK_STRING:{
+codestring(ls,&args,ls->t.seminfo.ts);
+luaX_next(ls);
+break;
+}
+default:{
+luaX_syntaxerror(ls,"function arguments expected");
+return;
+}
+}
+base=f->u.s.info;
+if(hasmultret(args.k))
+nparams=(-1);
+else{
+if(args.k!=VVOID)
+luaK_exp2nextreg(fs,&args);
+nparams=fs->freereg-(base+1);
+}
+init_exp(f,VCALL,luaK_codeABC(fs,OP_CALL,base,nparams+1,2));
+luaK_fixline(fs,line);
+fs->freereg=base+1;
+}
+static void prefixexp(LexState*ls,expdesc*v){
+switch(ls->t.token){
+case'(':{
+int line=ls->linenumber;
+luaX_next(ls);
+expr(ls,v);
+check_match(ls,')','(',line);
+luaK_dischargevars(ls->fs,v);
+return;
+}
+case TK_NAME:{
+singlevar(ls,v);
+return;
+}
+default:{
+luaX_syntaxerror(ls,"unexpected symbol");
+return;
+}
+}
+}
+static void primaryexp(LexState*ls,expdesc*v){
+FuncState*fs=ls->fs;
+prefixexp(ls,v);
+for(;;){
+switch(ls->t.token){
+case'.':{
+field(ls,v);
+break;
+}
+case'[':{
+expdesc key;
+luaK_exp2anyreg(fs,v);
+yindex(ls,&key);
+luaK_indexed(fs,v,&key);
+break;
+}
+case':':{
+expdesc key;
+luaX_next(ls);
+checkname(ls,&key);
+luaK_self(fs,v,&key);
+funcargs(ls,v);
+break;
+}
+case'(':case TK_STRING:case'{':{
+luaK_exp2nextreg(fs,v);
+funcargs(ls,v);
+break;
+}
+default:return;
+}
+}
+}
+static void simpleexp(LexState*ls,expdesc*v){
+switch(ls->t.token){
+case TK_NUMBER:{
+init_exp(v,VKNUM,0);
+v->u.nval=ls->t.seminfo.r;
+break;
+}
+case TK_STRING:{
+codestring(ls,v,ls->t.seminfo.ts);
+break;
+}
+case TK_NIL:{
+init_exp(v,VNIL,0);
+break;
+}
+case TK_TRUE:{
+init_exp(v,VTRUE,0);
+break;
+}
+case TK_FALSE:{
+init_exp(v,VFALSE,0);
+break;
+}
+case TK_DOTS:{
+FuncState*fs=ls->fs;
+check_condition(ls,fs->f->is_vararg,
+"cannot use "LUA_QL("...")" outside a vararg function");
+fs->f->is_vararg&=~4;
+init_exp(v,VVARARG,luaK_codeABC(fs,OP_VARARG,0,1,0));
+break;
+}
+case'{':{
+constructor(ls,v);
+return;
+}
+case TK_FUNCTION:{
+luaX_next(ls);
+body(ls,v,0,ls->linenumber);
+return;
+}
+default:{
+primaryexp(ls,v);
+return;
+}
+}
+luaX_next(ls);
+}
+static UnOpr getunopr(int op){
+switch(op){
+case TK_NOT:return OPR_NOT;
+case'-':return OPR_MINUS;
+case'#':return OPR_LEN;
+default:return OPR_NOUNOPR;
+}
+}
+static BinOpr getbinopr(int op){
+switch(op){
+case'+':return OPR_ADD;
+case'-':return OPR_SUB;
+case'*':return OPR_MUL;
+case'/':return OPR_DIV;
+case'%':return OPR_MOD;
+case'^':return OPR_POW;
+case TK_CONCAT:return OPR_CONCAT;
+case TK_NE:return OPR_NE;
+case TK_EQ:return OPR_EQ;
+case'<':return OPR_LT;
+case TK_LE:return OPR_LE;
+case'>':return OPR_GT;
+case TK_GE:return OPR_GE;
+case TK_AND:return OPR_AND;
+case TK_OR:return OPR_OR;
+default:return OPR_NOBINOPR;
+}
+}
+static const struct{
+lu_byte left;
+lu_byte right;
+}priority[]={
+{6,6},{6,6},{7,7},{7,7},{7,7},
+{10,9},{5,4},
+{3,3},{3,3},
+{3,3},{3,3},{3,3},{3,3},
+{2,2},{1,1}
+};
+static BinOpr subexpr(LexState*ls,expdesc*v,unsigned int limit){
+BinOpr op;
+UnOpr uop;
+enterlevel(ls);
+uop=getunopr(ls->t.token);
+if(uop!=OPR_NOUNOPR){
+luaX_next(ls);
+subexpr(ls,v,8);
+luaK_prefix(ls->fs,uop,v);
+}
+else simpleexp(ls,v);
+op=getbinopr(ls->t.token);
+while(op!=OPR_NOBINOPR&&priority[op].left>limit){
+expdesc v2;
+BinOpr nextop;
+luaX_next(ls);
+luaK_infix(ls->fs,op,v);
+nextop=subexpr(ls,&v2,priority[op].right);
+luaK_posfix(ls->fs,op,v,&v2);
+op=nextop;
+}
+leavelevel(ls);
+return op;
+}
+static void expr(LexState*ls,expdesc*v){
+subexpr(ls,v,0);
+}
+static int block_follow(int token){
+switch(token){
+case TK_ELSE:case TK_ELSEIF:case TK_END:
+case TK_UNTIL:case TK_EOS:
+return 1;
+default:return 0;
+}
+}
+static void block(LexState*ls){
+FuncState*fs=ls->fs;
+BlockCnt bl;
+enterblock(fs,&bl,0);
+chunk(ls);
+leaveblock(fs);
+}
+struct LHS_assign{
+struct LHS_assign*prev;
+expdesc v;
+};
+static void check_conflict(LexState*ls,struct LHS_assign*lh,expdesc*v){
+FuncState*fs=ls->fs;
+int extra=fs->freereg;
+int conflict=0;
+for(;lh;lh=lh->prev){
+if(lh->v.k==VINDEXED){
+if(lh->v.u.s.info==v->u.s.info){
+conflict=1;
+lh->v.u.s.info=extra;
+}
+if(lh->v.u.s.aux==v->u.s.info){
+conflict=1;
+lh->v.u.s.aux=extra;
+}
+}
+}
+if(conflict){
+luaK_codeABC(fs,OP_MOVE,fs->freereg,v->u.s.info,0);
+luaK_reserveregs(fs,1);
+}
+}
+static void assignment(LexState*ls,struct LHS_assign*lh,int nvars){
+expdesc e;
+check_condition(ls,VLOCAL<=lh->v.k&&lh->v.k<=VINDEXED,
+"syntax error");
+if(testnext(ls,',')){
+struct LHS_assign nv;
+nv.prev=lh;
+primaryexp(ls,&nv.v);
+if(nv.v.k==VLOCAL)
+check_conflict(ls,lh,&nv.v);
+luaY_checklimit(ls->fs,nvars,200-ls->L->nCcalls,
+"variables in assignment");
+assignment(ls,&nv,nvars+1);
+}
+else{
+int nexps;
+checknext(ls,'=');
+nexps=explist1(ls,&e);
+if(nexps!=nvars){
+adjust_assign(ls,nvars,nexps,&e);
+if(nexps>nvars)
+ls->fs->freereg-=nexps-nvars;
+}
+else{
+luaK_setoneret(ls->fs,&e);
+luaK_storevar(ls->fs,&lh->v,&e);
+return;
+}
+}
+init_exp(&e,VNONRELOC,ls->fs->freereg-1);
+luaK_storevar(ls->fs,&lh->v,&e);
+}
+static int cond(LexState*ls){
+expdesc v;
+expr(ls,&v);
+if(v.k==VNIL)v.k=VFALSE;
+luaK_goiftrue(ls->fs,&v);
+return v.f;
+}
+static void breakstat(LexState*ls){
+FuncState*fs=ls->fs;
+BlockCnt*bl=fs->bl;
+int upval=0;
+while(bl&&!bl->isbreakable){
+upval|=bl->upval;
+bl=bl->previous;
+}
+if(!bl)
+luaX_syntaxerror(ls,"no loop to break");
+if(upval)
+luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0);
+luaK_concat(fs,&bl->breaklist,luaK_jump(fs));
+}
+static void whilestat(LexState*ls,int line){
+FuncState*fs=ls->fs;
+int whileinit;
+int condexit;
+BlockCnt bl;
+luaX_next(ls);
+whileinit=luaK_getlabel(fs);
+condexit=cond(ls);
+enterblock(fs,&bl,1);
+checknext(ls,TK_DO);
+block(ls);
+luaK_patchlist(fs,luaK_jump(fs),whileinit);
+check_match(ls,TK_END,TK_WHILE,line);
+leaveblock(fs);
+luaK_patchtohere(fs,condexit);
+}
+static void repeatstat(LexState*ls,int line){
+int condexit;
+FuncState*fs=ls->fs;
+int repeat_init=luaK_getlabel(fs);
+BlockCnt bl1,bl2;
+enterblock(fs,&bl1,1);
+enterblock(fs,&bl2,0);
+luaX_next(ls);
+chunk(ls);
+check_match(ls,TK_UNTIL,TK_REPEAT,line);
+condexit=cond(ls);
+if(!bl2.upval){
+leaveblock(fs);
+luaK_patchlist(ls->fs,condexit,repeat_init);
+}
+else{
+breakstat(ls);
+luaK_patchtohere(ls->fs,condexit);
+leaveblock(fs);
+luaK_patchlist(ls->fs,luaK_jump(fs),repeat_init);
+}
+leaveblock(fs);
+}
+static int exp1(LexState*ls){
+expdesc e;
+int k;
+expr(ls,&e);
+k=e.k;
+luaK_exp2nextreg(ls->fs,&e);
+return k;
+}
+static void forbody(LexState*ls,int base,int line,int nvars,int isnum){
+BlockCnt bl;
+FuncState*fs=ls->fs;
+int prep,endfor;
+adjustlocalvars(ls,3);
+checknext(ls,TK_DO);
+prep=isnum?luaK_codeAsBx(fs,OP_FORPREP,base,(-1)):luaK_jump(fs);
+enterblock(fs,&bl,0);
+adjustlocalvars(ls,nvars);
+luaK_reserveregs(fs,nvars);
+block(ls);
+leaveblock(fs);
+luaK_patchtohere(fs,prep);
+endfor=(isnum)?luaK_codeAsBx(fs,OP_FORLOOP,base,(-1)):
+luaK_codeABC(fs,OP_TFORLOOP,base,0,nvars);
+luaK_fixline(fs,line);
+luaK_patchlist(fs,(isnum?endfor:luaK_jump(fs)),prep+1);
+}
+static void fornum(LexState*ls,TString*varname,int line){
+FuncState*fs=ls->fs;
+int base=fs->freereg;
+new_localvarliteral(ls,"(for index)",0);
+new_localvarliteral(ls,"(for limit)",1);
+new_localvarliteral(ls,"(for step)",2);
+new_localvar(ls,varname,3);
+checknext(ls,'=');
+exp1(ls);
+checknext(ls,',');
+exp1(ls);
+if(testnext(ls,','))
+exp1(ls);
+else{
+luaK_codeABx(fs,OP_LOADK,fs->freereg,luaK_numberK(fs,1));
+luaK_reserveregs(fs,1);
+}
+forbody(ls,base,line,1,1);
+}
+static void forlist(LexState*ls,TString*indexname){
+FuncState*fs=ls->fs;
+expdesc e;
+int nvars=0;
+int line;
+int base=fs->freereg;
+new_localvarliteral(ls,"(for generator)",nvars++);
+new_localvarliteral(ls,"(for state)",nvars++);
+new_localvarliteral(ls,"(for control)",nvars++);
+new_localvar(ls,indexname,nvars++);
+while(testnext(ls,','))
+new_localvar(ls,str_checkname(ls),nvars++);
+checknext(ls,TK_IN);
+line=ls->linenumber;
+adjust_assign(ls,3,explist1(ls,&e),&e);
+luaK_checkstack(fs,3);
+forbody(ls,base,line,nvars-3,0);
+}
+static void forstat(LexState*ls,int line){
+FuncState*fs=ls->fs;
+TString*varname;
+BlockCnt bl;
+enterblock(fs,&bl,1);
+luaX_next(ls);
+varname=str_checkname(ls);
+switch(ls->t.token){
+case'=':fornum(ls,varname,line);break;
+case',':case TK_IN:forlist(ls,varname);break;
+default:luaX_syntaxerror(ls,LUA_QL("=")" or "LUA_QL("in")" expected");
+}
+check_match(ls,TK_END,TK_FOR,line);
+leaveblock(fs);
+}
+static int test_then_block(LexState*ls){
+int condexit;
+luaX_next(ls);
+condexit=cond(ls);
+checknext(ls,TK_THEN);
+block(ls);
+return condexit;
+}
+static void ifstat(LexState*ls,int line){
+FuncState*fs=ls->fs;
+int flist;
+int escapelist=(-1);
+flist=test_then_block(ls);
+while(ls->t.token==TK_ELSEIF){
+luaK_concat(fs,&escapelist,luaK_jump(fs));
+luaK_patchtohere(fs,flist);
+flist=test_then_block(ls);
+}
+if(ls->t.token==TK_ELSE){
+luaK_concat(fs,&escapelist,luaK_jump(fs));
+luaK_patchtohere(fs,flist);
+luaX_next(ls);
+block(ls);
+}
+else
+luaK_concat(fs,&escapelist,flist);
+luaK_patchtohere(fs,escapelist);
+check_match(ls,TK_END,TK_IF,line);
+}
+static void localfunc(LexState*ls){
+expdesc v,b;
+FuncState*fs=ls->fs;
+new_localvar(ls,str_checkname(ls),0);
+init_exp(&v,VLOCAL,fs->freereg);
+luaK_reserveregs(fs,1);
+adjustlocalvars(ls,1);
+body(ls,&b,0,ls->linenumber);
+luaK_storevar(fs,&v,&b);
+getlocvar(fs,fs->nactvar-1).startpc=fs->pc;
+}
+static void localstat(LexState*ls){
+int nvars=0;
+int nexps;
+expdesc e;
+do{
+new_localvar(ls,str_checkname(ls),nvars++);
+}while(testnext(ls,','));
+if(testnext(ls,'='))
+nexps=explist1(ls,&e);
+else{
+e.k=VVOID;
+nexps=0;
+}
+adjust_assign(ls,nvars,nexps,&e);
+adjustlocalvars(ls,nvars);
+}
+static int funcname(LexState*ls,expdesc*v){
+int needself=0;
+singlevar(ls,v);
+while(ls->t.token=='.')
+field(ls,v);
+if(ls->t.token==':'){
+needself=1;
+field(ls,v);
+}
+return needself;
+}
+static void funcstat(LexState*ls,int line){
+int needself;
+expdesc v,b;
+luaX_next(ls);
+needself=funcname(ls,&v);
+body(ls,&b,needself,line);
+luaK_storevar(ls->fs,&v,&b);
+luaK_fixline(ls->fs,line);
+}
+static void exprstat(LexState*ls){
+FuncState*fs=ls->fs;
+struct LHS_assign v;
+primaryexp(ls,&v.v);
+if(v.v.k==VCALL)
+SETARG_C(getcode(fs,&v.v),1);
+else{
+v.prev=NULL;
+assignment(ls,&v,1);
+}
+}
+static void retstat(LexState*ls){
+FuncState*fs=ls->fs;
+expdesc e;
+int first,nret;
+luaX_next(ls);
+if(block_follow(ls->t.token)||ls->t.token==';')
+first=nret=0;
+else{
+nret=explist1(ls,&e);
+if(hasmultret(e.k)){
+luaK_setmultret(fs,&e);
+if(e.k==VCALL&&nret==1){
+SET_OPCODE(getcode(fs,&e),OP_TAILCALL);
+}
+first=fs->nactvar;
+nret=(-1);
+}
+else{
+if(nret==1)
+first=luaK_exp2anyreg(fs,&e);
+else{
+luaK_exp2nextreg(fs,&e);
+first=fs->nactvar;
+}
+}
+}
+luaK_ret(fs,first,nret);
+}
+static int statement(LexState*ls){
+int line=ls->linenumber;
+switch(ls->t.token){
+case TK_IF:{
+ifstat(ls,line);
+return 0;
+}
+case TK_WHILE:{
+whilestat(ls,line);
+return 0;
+}
+case TK_DO:{
+luaX_next(ls);
+block(ls);
+check_match(ls,TK_END,TK_DO,line);
+return 0;
+}
+case TK_FOR:{
+forstat(ls,line);
+return 0;
+}
+case TK_REPEAT:{
+repeatstat(ls,line);
+return 0;
+}
+case TK_FUNCTION:{
+funcstat(ls,line);
+return 0;
+}
+case TK_LOCAL:{
+luaX_next(ls);
+if(testnext(ls,TK_FUNCTION))
+localfunc(ls);
+else
+localstat(ls);
+return 0;
+}
+case TK_RETURN:{
+retstat(ls);
+return 1;
+}
+case TK_BREAK:{
+luaX_next(ls);
+breakstat(ls);
+return 1;
+}
+default:{
+exprstat(ls);
+return 0;
+}
+}
+}
+static void chunk(LexState*ls){
+int islast=0;
+enterlevel(ls);
+while(!islast&&!block_follow(ls->t.token)){
+islast=statement(ls);
+testnext(ls,';');
+ls->fs->freereg=ls->fs->nactvar;
+}
+leavelevel(ls);
+}
+static const TValue*luaV_tonumber(const TValue*obj,TValue*n){
+lua_Number num;
+if(ttisnumber(obj))return obj;
+if(ttisstring(obj)&&luaO_str2d(svalue(obj),&num)){
+setnvalue(n,num);
+return n;
+}
+else
+return NULL;
+}
+static int luaV_tostring(lua_State*L,StkId obj){
+if(!ttisnumber(obj))
+return 0;
+else{
+char s[32];
+lua_Number n=nvalue(obj);
+lua_number2str(s,n);
+setsvalue(L,obj,luaS_new(L,s));
+return 1;
+}
+}
+static void callTMres(lua_State*L,StkId res,const TValue*f,
+const TValue*p1,const TValue*p2){
+ptrdiff_t result=savestack(L,res);
+setobj(L,L->top,f);
+setobj(L,L->top+1,p1);
+setobj(L,L->top+2,p2);
+luaD_checkstack(L,3);
+L->top+=3;
+luaD_call(L,L->top-3,1);
+res=restorestack(L,result);
+L->top--;
+setobj(L,res,L->top);
+}
+static void callTM(lua_State*L,const TValue*f,const TValue*p1,
+const TValue*p2,const TValue*p3){
+setobj(L,L->top,f);
+setobj(L,L->top+1,p1);
+setobj(L,L->top+2,p2);
+setobj(L,L->top+3,p3);
+luaD_checkstack(L,4);
+L->top+=4;
+luaD_call(L,L->top-4,0);
+}
+static void luaV_gettable(lua_State*L,const TValue*t,TValue*key,StkId val){
+int loop;
+for(loop=0;loop<100;loop++){
+const TValue*tm;
+if(ttistable(t)){
+Table*h=hvalue(t);
+const TValue*res=luaH_get(h,key);
+if(!ttisnil(res)||
+(tm=fasttm(L,h->metatable,TM_INDEX))==NULL){
+setobj(L,val,res);
+return;
+}
+}
+else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_INDEX)))
+luaG_typeerror(L,t,"index");
+if(ttisfunction(tm)){
+callTMres(L,val,tm,t,key);
+return;
+}
+t=tm;
+}
+luaG_runerror(L,"loop in gettable");
+}
+static void luaV_settable(lua_State*L,const TValue*t,TValue*key,StkId val){
+int loop;
+TValue temp;
+for(loop=0;loop<100;loop++){
+const TValue*tm;
+if(ttistable(t)){
+Table*h=hvalue(t);
+TValue*oldval=luaH_set(L,h,key);
+if(!ttisnil(oldval)||
+(tm=fasttm(L,h->metatable,TM_NEWINDEX))==NULL){
+setobj(L,oldval,val);
+h->flags=0;
+luaC_barriert(L,h,val);
+return;
+}
+}
+else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_NEWINDEX)))
+luaG_typeerror(L,t,"index");
+if(ttisfunction(tm)){
+callTM(L,tm,t,key,val);
+return;
+}
+setobj(L,&temp,tm);
+t=&temp;
+}
+luaG_runerror(L,"loop in settable");
+}
+static int call_binTM(lua_State*L,const TValue*p1,const TValue*p2,
+StkId res,TMS event){
+const TValue*tm=luaT_gettmbyobj(L,p1,event);
+if(ttisnil(tm))
+tm=luaT_gettmbyobj(L,p2,event);
+if(ttisnil(tm))return 0;
+callTMres(L,res,tm,p1,p2);
+return 1;
+}
+static const TValue*get_compTM(lua_State*L,Table*mt1,Table*mt2,
+TMS event){
+const TValue*tm1=fasttm(L,mt1,event);
+const TValue*tm2;
+if(tm1==NULL)return NULL;
+if(mt1==mt2)return tm1;
+tm2=fasttm(L,mt2,event);
+if(tm2==NULL)return NULL;
+if(luaO_rawequalObj(tm1,tm2))
+return tm1;
+return NULL;
+}
+static int call_orderTM(lua_State*L,const TValue*p1,const TValue*p2,
+TMS event){
+const TValue*tm1=luaT_gettmbyobj(L,p1,event);
+const TValue*tm2;
+if(ttisnil(tm1))return-1;
+tm2=luaT_gettmbyobj(L,p2,event);
+if(!luaO_rawequalObj(tm1,tm2))
+return-1;
+callTMres(L,L->top,tm1,p1,p2);
+return!l_isfalse(L->top);
+}
+static int l_strcmp(const TString*ls,const TString*rs){
+const char*l=getstr(ls);
+size_t ll=ls->tsv.len;
+const char*r=getstr(rs);
+size_t lr=rs->tsv.len;
+for(;;){
+int temp=strcoll(l,r);
+if(temp!=0)return temp;
+else{
+size_t len=strlen(l);
+if(len==lr)
+return(len==ll)?0:1;
+else if(len==ll)
+return-1;
+len++;
+l+=len;ll-=len;r+=len;lr-=len;
+}
+}
+}
+static int luaV_lessthan(lua_State*L,const TValue*l,const TValue*r){
+int res;
+if(ttype(l)!=ttype(r))
+return luaG_ordererror(L,l,r);
+else if(ttisnumber(l))
+return luai_numlt(nvalue(l),nvalue(r));
+else if(ttisstring(l))
+return l_strcmp(rawtsvalue(l),rawtsvalue(r))<0;
+else if((res=call_orderTM(L,l,r,TM_LT))!=-1)
+return res;
+return luaG_ordererror(L,l,r);
+}
+static int lessequal(lua_State*L,const TValue*l,const TValue*r){
+int res;
+if(ttype(l)!=ttype(r))
+return luaG_ordererror(L,l,r);
+else if(ttisnumber(l))
+return luai_numle(nvalue(l),nvalue(r));
+else if(ttisstring(l))
+return l_strcmp(rawtsvalue(l),rawtsvalue(r))<=0;
+else if((res=call_orderTM(L,l,r,TM_LE))!=-1)
+return res;
+else if((res=call_orderTM(L,r,l,TM_LT))!=-1)
+return!res;
+return luaG_ordererror(L,l,r);
+}
+static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2){
+const TValue*tm;
+switch(ttype(t1)){
+case 0:return 1;
+case 3:return luai_numeq(nvalue(t1),nvalue(t2));
+case 1:return bvalue(t1)==bvalue(t2);
+case 2:return pvalue(t1)==pvalue(t2);
+case 7:{
+if(uvalue(t1)==uvalue(t2))return 1;
+tm=get_compTM(L,uvalue(t1)->metatable,uvalue(t2)->metatable,
+TM_EQ);
+break;
+}
+case 5:{
+if(hvalue(t1)==hvalue(t2))return 1;
+tm=get_compTM(L,hvalue(t1)->metatable,hvalue(t2)->metatable,TM_EQ);
+break;
+}
+default:return gcvalue(t1)==gcvalue(t2);
+}
+if(tm==NULL)return 0;
+callTMres(L,L->top,tm,t1,t2);
+return!l_isfalse(L->top);
+}
+static void luaV_concat(lua_State*L,int total,int last){
+do{
+StkId top=L->base+last+1;
+int n=2;
+if(!(ttisstring(top-2)||ttisnumber(top-2))||!tostring(L,top-1)){
+if(!call_binTM(L,top-2,top-1,top-2,TM_CONCAT))
+luaG_concaterror(L,top-2,top-1);
+}else if(tsvalue(top-1)->len==0)
+(void)tostring(L,top-2);
+else{
+size_t tl=tsvalue(top-1)->len;
+char*buffer;
+int i;
+for(n=1;n<total&&tostring(L,top-n-1);n++){
+size_t l=tsvalue(top-n-1)->len;
+if(l>=((size_t)(~(size_t)0)-2)-tl)luaG_runerror(L,"string length overflow");
+tl+=l;
+}
+buffer=luaZ_openspace(L,&G(L)->buff,tl);
+tl=0;
+for(i=n;i>0;i--){
+size_t l=tsvalue(top-i)->len;
+memcpy(buffer+tl,svalue(top-i),l);
+tl+=l;
+}
+setsvalue(L,top-n,luaS_newlstr(L,buffer,tl));
+}
+total-=n-1;
+last-=n-1;
+}while(total>1);
+}
+static void Arith(lua_State*L,StkId ra,const TValue*rb,
+const TValue*rc,TMS op){
+TValue tempb,tempc;
+const TValue*b,*c;
+if((b=luaV_tonumber(rb,&tempb))!=NULL&&
+(c=luaV_tonumber(rc,&tempc))!=NULL){
+lua_Number nb=nvalue(b),nc=nvalue(c);
+switch(op){
+case TM_ADD:setnvalue(ra,luai_numadd(nb,nc));break;
+case TM_SUB:setnvalue(ra,luai_numsub(nb,nc));break;
+case TM_MUL:setnvalue(ra,luai_nummul(nb,nc));break;
+case TM_DIV:setnvalue(ra,luai_numdiv(nb,nc));break;
+case TM_MOD:setnvalue(ra,luai_nummod(nb,nc));break;
+case TM_POW:setnvalue(ra,luai_numpow(nb,nc));break;
+case TM_UNM:setnvalue(ra,luai_numunm(nb));break;
+default:break;
+}
+}
+else if(!call_binTM(L,rb,rc,ra,op))
+luaG_aritherror(L,rb,rc);
+}
+#define runtime_check(L,c){if(!(c))break;}
+#define RA(i)(base+GETARG_A(i))
+#define RB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgR,base+GETARG_B(i))
+#define RKB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_B(i))?k+INDEXK(GETARG_B(i)):base+GETARG_B(i))
+#define RKC(i)check_exp(getCMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_C(i))?k+INDEXK(GETARG_C(i)):base+GETARG_C(i))
+#define KBx(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,k+GETARG_Bx(i))
+#define dojump(L,pc,i){(pc)+=(i);}
+#define Protect(x){L->savedpc=pc;{x;};base=L->base;}
+#define arith_op(op,tm){TValue*rb=RKB(i);TValue*rc=RKC(i);if(ttisnumber(rb)&&ttisnumber(rc)){lua_Number nb=nvalue(rb),nc=nvalue(rc);setnvalue(ra,op(nb,nc));}else Protect(Arith(L,ra,rb,rc,tm));}
+static void luaV_execute(lua_State*L,int nexeccalls){
+LClosure*cl;
+StkId base;
+TValue*k;
+const Instruction*pc;
+reentry:
+pc=L->savedpc;
+cl=&clvalue(L->ci->func)->l;
+base=L->base;
+k=cl->p->k;
+for(;;){
+const Instruction i=*pc++;
+StkId ra;
+ra=RA(i);
+switch(GET_OPCODE(i)){
+case OP_MOVE:{
+setobj(L,ra,RB(i));
+continue;
+}
+case OP_LOADK:{
+setobj(L,ra,KBx(i));
+continue;
+}
+case OP_LOADBOOL:{
+setbvalue(ra,GETARG_B(i));
+if(GETARG_C(i))pc++;
+continue;
+}
+case OP_LOADNIL:{
+TValue*rb=RB(i);
+do{
+setnilvalue(rb--);
+}while(rb>=ra);
+continue;
+}
+case OP_GETUPVAL:{
+int b=GETARG_B(i);
+setobj(L,ra,cl->upvals[b]->v);
+continue;
+}
+case OP_GETGLOBAL:{
+TValue g;
+TValue*rb=KBx(i);
+sethvalue(L,&g,cl->env);
+Protect(luaV_gettable(L,&g,rb,ra));
+continue;
+}
+case OP_GETTABLE:{
+Protect(luaV_gettable(L,RB(i),RKC(i),ra));
+continue;
+}
+case OP_SETGLOBAL:{
+TValue g;
+sethvalue(L,&g,cl->env);
+Protect(luaV_settable(L,&g,KBx(i),ra));
+continue;
+}
+case OP_SETUPVAL:{
+UpVal*uv=cl->upvals[GETARG_B(i)];
+setobj(L,uv->v,ra);
+luaC_barrier(L,uv,ra);
+continue;
+}
+case OP_SETTABLE:{
+Protect(luaV_settable(L,ra,RKB(i),RKC(i)));
+continue;
+}
+case OP_NEWTABLE:{
+int b=GETARG_B(i);
+int c=GETARG_C(i);
+sethvalue(L,ra,luaH_new(L,luaO_fb2int(b),luaO_fb2int(c)));
+Protect(luaC_checkGC(L));
+continue;
+}
+case OP_SELF:{
+StkId rb=RB(i);
+setobj(L,ra+1,rb);
+Protect(luaV_gettable(L,rb,RKC(i),ra));
+continue;
+}
+case OP_ADD:{
+arith_op(luai_numadd,TM_ADD);
+continue;
+}
+case OP_SUB:{
+arith_op(luai_numsub,TM_SUB);
+continue;
+}
+case OP_MUL:{
+arith_op(luai_nummul,TM_MUL);
+continue;
+}
+case OP_DIV:{
+arith_op(luai_numdiv,TM_DIV);
+continue;
+}
+case OP_MOD:{
+arith_op(luai_nummod,TM_MOD);
+continue;
+}
+case OP_POW:{
+arith_op(luai_numpow,TM_POW);
+continue;
+}
+case OP_UNM:{
+TValue*rb=RB(i);
+if(ttisnumber(rb)){
+lua_Number nb=nvalue(rb);
+setnvalue(ra,luai_numunm(nb));
+}
+else{
+Protect(Arith(L,ra,rb,rb,TM_UNM));
+}
+continue;
+}
+case OP_NOT:{
+int res=l_isfalse(RB(i));
+setbvalue(ra,res);
+continue;
+}
+case OP_LEN:{
+const TValue*rb=RB(i);
+switch(ttype(rb)){
+case 5:{
+setnvalue(ra,cast_num(luaH_getn(hvalue(rb))));
+break;
+}
+case 4:{
+setnvalue(ra,cast_num(tsvalue(rb)->len));
+break;
+}
+default:{
+Protect(
+if(!call_binTM(L,rb,(&luaO_nilobject_),ra,TM_LEN))
+luaG_typeerror(L,rb,"get length of");
+)
+}
+}
+continue;
+}
+case OP_CONCAT:{
+int b=GETARG_B(i);
+int c=GETARG_C(i);
+Protect(luaV_concat(L,c-b+1,c);luaC_checkGC(L));
+setobj(L,RA(i),base+b);
+continue;
+}
+case OP_JMP:{
+dojump(L,pc,GETARG_sBx(i));
+continue;
+}
+case OP_EQ:{
+TValue*rb=RKB(i);
+TValue*rc=RKC(i);
+Protect(
+if(equalobj(L,rb,rc)==GETARG_A(i))
+dojump(L,pc,GETARG_sBx(*pc));
+)
+pc++;
+continue;
+}
+case OP_LT:{
+Protect(
+if(luaV_lessthan(L,RKB(i),RKC(i))==GETARG_A(i))
+dojump(L,pc,GETARG_sBx(*pc));
+)
+pc++;
+continue;
+}
+case OP_LE:{
+Protect(
+if(lessequal(L,RKB(i),RKC(i))==GETARG_A(i))
+dojump(L,pc,GETARG_sBx(*pc));
+)
+pc++;
+continue;
+}
+case OP_TEST:{
+if(l_isfalse(ra)!=GETARG_C(i))
+dojump(L,pc,GETARG_sBx(*pc));
+pc++;
+continue;
+}
+case OP_TESTSET:{
+TValue*rb=RB(i);
+if(l_isfalse(rb)!=GETARG_C(i)){
+setobj(L,ra,rb);
+dojump(L,pc,GETARG_sBx(*pc));
+}
+pc++;
+continue;
+}
+case OP_CALL:{
+int b=GETARG_B(i);
+int nresults=GETARG_C(i)-1;
+if(b!=0)L->top=ra+b;
+L->savedpc=pc;
+switch(luaD_precall(L,ra,nresults)){
+case 0:{
+nexeccalls++;
+goto reentry;
+}
+case 1:{
+if(nresults>=0)L->top=L->ci->top;
+base=L->base;
+continue;
+}
+default:{
+return;
+}
+}
+}
+case OP_TAILCALL:{
+int b=GETARG_B(i);
+if(b!=0)L->top=ra+b;
+L->savedpc=pc;
+switch(luaD_precall(L,ra,(-1))){
+case 0:{
+CallInfo*ci=L->ci-1;
+int aux;
+StkId func=ci->func;
+StkId pfunc=(ci+1)->func;
+if(L->openupval)luaF_close(L,ci->base);
+L->base=ci->base=ci->func+((ci+1)->base-pfunc);
+for(aux=0;pfunc+aux<L->top;aux++)
+setobj(L,func+aux,pfunc+aux);
+ci->top=L->top=func+aux;
+ci->savedpc=L->savedpc;
+ci->tailcalls++;
+L->ci--;
+goto reentry;
+}
+case 1:{
+base=L->base;
+continue;
+}
+default:{
+return;
+}
+}
+}
+case OP_RETURN:{
+int b=GETARG_B(i);
+if(b!=0)L->top=ra+b-1;
+if(L->openupval)luaF_close(L,base);
+L->savedpc=pc;
+b=luaD_poscall(L,ra);
+if(--nexeccalls==0)
+return;
+else{
+if(b)L->top=L->ci->top;
+goto reentry;
+}
+}
+case OP_FORLOOP:{
+lua_Number step=nvalue(ra+2);
+lua_Number idx=luai_numadd(nvalue(ra),step);
+lua_Number limit=nvalue(ra+1);
+if(luai_numlt(0,step)?luai_numle(idx,limit)
+:luai_numle(limit,idx)){
+dojump(L,pc,GETARG_sBx(i));
+setnvalue(ra,idx);
+setnvalue(ra+3,idx);
+}
+continue;
+}
+case OP_FORPREP:{
+const TValue*init=ra;
+const TValue*plimit=ra+1;
+const TValue*pstep=ra+2;
+L->savedpc=pc;
+if(!tonumber(init,ra))
+luaG_runerror(L,LUA_QL("for")" initial value must be a number");
+else if(!tonumber(plimit,ra+1))
+luaG_runerror(L,LUA_QL("for")" limit must be a number");
+else if(!tonumber(pstep,ra+2))
+luaG_runerror(L,LUA_QL("for")" step must be a number");
+setnvalue(ra,luai_numsub(nvalue(ra),nvalue(pstep)));
+dojump(L,pc,GETARG_sBx(i));
+continue;
+}
+case OP_TFORLOOP:{
+StkId cb=ra+3;
+setobj(L,cb+2,ra+2);
+setobj(L,cb+1,ra+1);
+setobj(L,cb,ra);
+L->top=cb+3;
+Protect(luaD_call(L,cb,GETARG_C(i)));
+L->top=L->ci->top;
+cb=RA(i)+3;
+if(!ttisnil(cb)){
+setobj(L,cb-1,cb);
+dojump(L,pc,GETARG_sBx(*pc));
+}
+pc++;
+continue;
+}
+case OP_SETLIST:{
+int n=GETARG_B(i);
+int c=GETARG_C(i);
+int last;
+Table*h;
+if(n==0){
+n=cast_int(L->top-ra)-1;
+L->top=L->ci->top;
+}
+if(c==0)c=cast_int(*pc++);
+runtime_check(L,ttistable(ra));
+h=hvalue(ra);
+last=((c-1)*50)+n;
+if(last>h->sizearray)
+luaH_resizearray(L,h,last);
+for(;n>0;n--){
+TValue*val=ra+n;
+setobj(L,luaH_setnum(L,h,last--),val);
+luaC_barriert(L,h,val);
+}
+continue;
+}
+case OP_CLOSE:{
+luaF_close(L,ra);
+continue;
+}
+case OP_CLOSURE:{
+Proto*p;
+Closure*ncl;
+int nup,j;
+p=cl->p->p[GETARG_Bx(i)];
+nup=p->nups;
+ncl=luaF_newLclosure(L,nup,cl->env);
+ncl->l.p=p;
+for(j=0;j<nup;j++,pc++){
+if(GET_OPCODE(*pc)==OP_GETUPVAL)
+ncl->l.upvals[j]=cl->upvals[GETARG_B(*pc)];
+else{
+ncl->l.upvals[j]=luaF_findupval(L,base+GETARG_B(*pc));
+}
+}
+setclvalue(L,ra,ncl);
+Protect(luaC_checkGC(L));
+continue;
+}
+case OP_VARARG:{
+int b=GETARG_B(i)-1;
+int j;
+CallInfo*ci=L->ci;
+int n=cast_int(ci->base-ci->func)-cl->p->numparams-1;
+if(b==(-1)){
+Protect(luaD_checkstack(L,n));
+ra=RA(i);
+b=n;
+L->top=ra+n;
+}
+for(j=0;j<b;j++){
+if(j<n){
+setobj(L,ra+j,ci->base-n+j);
+}
+else{
+setnilvalue(ra+j);
+}
+}
+continue;
+}
+}
+}
+}
+#define api_checknelems(L,n)luai_apicheck(L,(n)<=(L->top-L->base))
+#define api_checkvalidindex(L,i)luai_apicheck(L,(i)!=(&luaO_nilobject_))
+#define api_incr_top(L){luai_apicheck(L,L->top<L->ci->top);L->top++;}
+static TValue*index2adr(lua_State*L,int idx){
+if(idx>0){
+TValue*o=L->base+(idx-1);
+luai_apicheck(L,idx<=L->ci->top-L->base);
+if(o>=L->top)return cast(TValue*,(&luaO_nilobject_));
+else return o;
+}
+else if(idx>(-10000)){
+luai_apicheck(L,idx!=0&&-idx<=L->top-L->base);
+return L->top+idx;
+}
+else switch(idx){
+case(-10000):return registry(L);
+case(-10001):{
+Closure*func=curr_func(L);
+sethvalue(L,&L->env,func->c.env);
+return&L->env;
+}
+case(-10002):return gt(L);
+default:{
+Closure*func=curr_func(L);
+idx=(-10002)-idx;
+return(idx<=func->c.nupvalues)
+?&func->c.upvalue[idx-1]
+:cast(TValue*,(&luaO_nilobject_));
+}
+}
+}
+static Table*getcurrenv(lua_State*L){
+if(L->ci==L->base_ci)
+return hvalue(gt(L));
+else{
+Closure*func=curr_func(L);
+return func->c.env;
+}
+}
+static int lua_checkstack(lua_State*L,int size){
+int res=1;
+if(size>8000||(L->top-L->base+size)>8000)
+res=0;
+else if(size>0){
+luaD_checkstack(L,size);
+if(L->ci->top<L->top+size)
+L->ci->top=L->top+size;
+}
+return res;
+}
+static lua_CFunction lua_atpanic(lua_State*L,lua_CFunction panicf){
+lua_CFunction old;
+old=G(L)->panic;
+G(L)->panic=panicf;
+return old;
+}
+static int lua_gettop(lua_State*L){
+return cast_int(L->top-L->base);
+}
+static void lua_settop(lua_State*L,int idx){
+if(idx>=0){
+luai_apicheck(L,idx<=L->stack_last-L->base);
+while(L->top<L->base+idx)
+setnilvalue(L->top++);
+L->top=L->base+idx;
+}
+else{
+luai_apicheck(L,-(idx+1)<=(L->top-L->base));
+L->top+=idx+1;
+}
+}
+static void lua_remove(lua_State*L,int idx){
+StkId p;
+p=index2adr(L,idx);
+api_checkvalidindex(L,p);
+while(++p<L->top)setobj(L,p-1,p);
+L->top--;
+}
+static void lua_insert(lua_State*L,int idx){
+StkId p;
+StkId q;
+p=index2adr(L,idx);
+api_checkvalidindex(L,p);
+for(q=L->top;q>p;q--)setobj(L,q,q-1);
+setobj(L,p,L->top);
+}
+static void lua_replace(lua_State*L,int idx){
+StkId o;
+if(idx==(-10001)&&L->ci==L->base_ci)
+luaG_runerror(L,"no calling environment");
+api_checknelems(L,1);
+o=index2adr(L,idx);
+api_checkvalidindex(L,o);
+if(idx==(-10001)){
+Closure*func=curr_func(L);
+luai_apicheck(L,ttistable(L->top-1));
+func->c.env=hvalue(L->top-1);
+luaC_barrier(L,func,L->top-1);
+}
+else{
+setobj(L,o,L->top-1);
+if(idx<(-10002))
+luaC_barrier(L,curr_func(L),L->top-1);
+}
+L->top--;
+}
+static void lua_pushvalue(lua_State*L,int idx){
+setobj(L,L->top,index2adr(L,idx));
+api_incr_top(L);
+}
+static int lua_type(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+return(o==(&luaO_nilobject_))?(-1):ttype(o);
+}
+static const char*lua_typename(lua_State*L,int t){
+UNUSED(L);
+return(t==(-1))?"no value":luaT_typenames[t];
+}
+static int lua_iscfunction(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+return iscfunction(o);
+}
+static int lua_isnumber(lua_State*L,int idx){
+TValue n;
+const TValue*o=index2adr(L,idx);
+return tonumber(o,&n);
+}
+static int lua_isstring(lua_State*L,int idx){
+int t=lua_type(L,idx);
+return(t==4||t==3);
+}
+static int lua_rawequal(lua_State*L,int index1,int index2){
+StkId o1=index2adr(L,index1);
+StkId o2=index2adr(L,index2);
+return(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0
+:luaO_rawequalObj(o1,o2);
+}
+static int lua_lessthan(lua_State*L,int index1,int index2){
+StkId o1,o2;
+int i;
+o1=index2adr(L,index1);
+o2=index2adr(L,index2);
+i=(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0
+:luaV_lessthan(L,o1,o2);
+return i;
+}
+static lua_Number lua_tonumber(lua_State*L,int idx){
+TValue n;
+const TValue*o=index2adr(L,idx);
+if(tonumber(o,&n))
+return nvalue(o);
+else
+return 0;
+}
+static lua_Integer lua_tointeger(lua_State*L,int idx){
+TValue n;
+const TValue*o=index2adr(L,idx);
+if(tonumber(o,&n)){
+lua_Integer res;
+lua_Number num=nvalue(o);
+lua_number2integer(res,num);
+return res;
+}
+else
+return 0;
+}
+static int lua_toboolean(lua_State*L,int idx){
+const TValue*o=index2adr(L,idx);
+return!l_isfalse(o);
+}
+static const char*lua_tolstring(lua_State*L,int idx,size_t*len){
+StkId o=index2adr(L,idx);
+if(!ttisstring(o)){
+if(!luaV_tostring(L,o)){
+if(len!=NULL)*len=0;
+return NULL;
+}
+luaC_checkGC(L);
+o=index2adr(L,idx);
+}
+if(len!=NULL)*len=tsvalue(o)->len;
+return svalue(o);
+}
+static size_t lua_objlen(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+switch(ttype(o)){
+case 4:return tsvalue(o)->len;
+case 7:return uvalue(o)->len;
+case 5:return luaH_getn(hvalue(o));
+case 3:{
+size_t l;
+l=(luaV_tostring(L,o)?tsvalue(o)->len:0);
+return l;
+}
+default:return 0;
+}
+}
+static lua_CFunction lua_tocfunction(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+return(!iscfunction(o))?NULL:clvalue(o)->c.f;
+}
+static void*lua_touserdata(lua_State*L,int idx){
+StkId o=index2adr(L,idx);
+switch(ttype(o)){
+case 7:return(rawuvalue(o)+1);
+case 2:return pvalue(o);
+default:return NULL;
+}
+}
+static void lua_pushnil(lua_State*L){
+setnilvalue(L->top);
+api_incr_top(L);
+}
+static void lua_pushnumber(lua_State*L,lua_Number n){
+setnvalue(L->top,n);
+api_incr_top(L);
+}
+static void lua_pushinteger(lua_State*L,lua_Integer n){
+setnvalue(L->top,cast_num(n));
+api_incr_top(L);
+}
+static void lua_pushlstring(lua_State*L,const char*s,size_t len){
+luaC_checkGC(L);
+setsvalue(L,L->top,luaS_newlstr(L,s,len));
+api_incr_top(L);
+}
+static void lua_pushstring(lua_State*L,const char*s){
+if(s==NULL)
+lua_pushnil(L);
+else
+lua_pushlstring(L,s,strlen(s));
+}
+static const char*lua_pushvfstring(lua_State*L,const char*fmt,
+va_list argp){
+const char*ret;
+luaC_checkGC(L);
+ret=luaO_pushvfstring(L,fmt,argp);
+return ret;
+}
+static const char*lua_pushfstring(lua_State*L,const char*fmt,...){
+const char*ret;
+va_list argp;
+luaC_checkGC(L);
+va_start(argp,fmt);
+ret=luaO_pushvfstring(L,fmt,argp);
+va_end(argp);
+return ret;
+}
+static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n){
+Closure*cl;
+luaC_checkGC(L);
+api_checknelems(L,n);
+cl=luaF_newCclosure(L,n,getcurrenv(L));
+cl->c.f=fn;
+L->top-=n;
+while(n--)
+setobj(L,&cl->c.upvalue[n],L->top+n);
+setclvalue(L,L->top,cl);
+api_incr_top(L);
+}
+static void lua_pushboolean(lua_State*L,int b){
+setbvalue(L->top,(b!=0));
+api_incr_top(L);
+}
+static int lua_pushthread(lua_State*L){
+setthvalue(L,L->top,L);
+api_incr_top(L);
+return(G(L)->mainthread==L);
+}
+static void lua_gettable(lua_State*L,int idx){
+StkId t;
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+luaV_gettable(L,t,L->top-1,L->top-1);
+}
+static void lua_getfield(lua_State*L,int idx,const char*k){
+StkId t;
+TValue key;
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+setsvalue(L,&key,luaS_new(L,k));
+luaV_gettable(L,t,&key,L->top);
+api_incr_top(L);
+}
+static void lua_rawget(lua_State*L,int idx){
+StkId t;
+t=index2adr(L,idx);
+luai_apicheck(L,ttistable(t));
+setobj(L,L->top-1,luaH_get(hvalue(t),L->top-1));
+}
+static void lua_rawgeti(lua_State*L,int idx,int n){
+StkId o;
+o=index2adr(L,idx);
+luai_apicheck(L,ttistable(o));
+setobj(L,L->top,luaH_getnum(hvalue(o),n));
+api_incr_top(L);
+}
+static void lua_createtable(lua_State*L,int narray,int nrec){
+luaC_checkGC(L);
+sethvalue(L,L->top,luaH_new(L,narray,nrec));
+api_incr_top(L);
+}
+static int lua_getmetatable(lua_State*L,int objindex){
+const TValue*obj;
+Table*mt=NULL;
+int res;
+obj=index2adr(L,objindex);
+switch(ttype(obj)){
+case 5:
+mt=hvalue(obj)->metatable;
+break;
+case 7:
+mt=uvalue(obj)->metatable;
+break;
+default:
+mt=G(L)->mt[ttype(obj)];
+break;
+}
+if(mt==NULL)
+res=0;
+else{
+sethvalue(L,L->top,mt);
+api_incr_top(L);
+res=1;
+}
+return res;
+}
+static void lua_getfenv(lua_State*L,int idx){
+StkId o;
+o=index2adr(L,idx);
+api_checkvalidindex(L,o);
+switch(ttype(o)){
+case 6:
+sethvalue(L,L->top,clvalue(o)->c.env);
+break;
+case 7:
+sethvalue(L,L->top,uvalue(o)->env);
+break;
+case 8:
+setobj(L,L->top,gt(thvalue(o)));
+break;
+default:
+setnilvalue(L->top);
+break;
+}
+api_incr_top(L);
+}
+static void lua_settable(lua_State*L,int idx){
+StkId t;
+api_checknelems(L,2);
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+luaV_settable(L,t,L->top-2,L->top-1);
+L->top-=2;
+}
+static void lua_setfield(lua_State*L,int idx,const char*k){
+StkId t;
+TValue key;
+api_checknelems(L,1);
+t=index2adr(L,idx);
+api_checkvalidindex(L,t);
+setsvalue(L,&key,luaS_new(L,k));
+luaV_settable(L,t,&key,L->top-1);
+L->top--;
+}
+static void lua_rawset(lua_State*L,int idx){
+StkId t;
+api_checknelems(L,2);
+t=index2adr(L,idx);
+luai_apicheck(L,ttistable(t));
+setobj(L,luaH_set(L,hvalue(t),L->top-2),L->top-1);
+luaC_barriert(L,hvalue(t),L->top-1);
+L->top-=2;
+}
+static void lua_rawseti(lua_State*L,int idx,int n){
+StkId o;
+api_checknelems(L,1);
+o=index2adr(L,idx);
+luai_apicheck(L,ttistable(o));
+setobj(L,luaH_setnum(L,hvalue(o),n),L->top-1);
+luaC_barriert(L,hvalue(o),L->top-1);
+L->top--;
+}
+static int lua_setmetatable(lua_State*L,int objindex){
+TValue*obj;
+Table*mt;
+api_checknelems(L,1);
+obj=index2adr(L,objindex);
+api_checkvalidindex(L,obj);
+if(ttisnil(L->top-1))
+mt=NULL;
+else{
+luai_apicheck(L,ttistable(L->top-1));
+mt=hvalue(L->top-1);
+}
+switch(ttype(obj)){
+case 5:{
+hvalue(obj)->metatable=mt;
+if(mt)
+luaC_objbarriert(L,hvalue(obj),mt);
+break;
+}
+case 7:{
+uvalue(obj)->metatable=mt;
+if(mt)
+luaC_objbarrier(L,rawuvalue(obj),mt);
+break;
+}
+default:{
+G(L)->mt[ttype(obj)]=mt;
+break;
+}
+}
+L->top--;
+return 1;
+}
+static int lua_setfenv(lua_State*L,int idx){
+StkId o;
+int res=1;
+api_checknelems(L,1);
+o=index2adr(L,idx);
+api_checkvalidindex(L,o);
+luai_apicheck(L,ttistable(L->top-1));
+switch(ttype(o)){
+case 6:
+clvalue(o)->c.env=hvalue(L->top-1);
+break;
+case 7:
+uvalue(o)->env=hvalue(L->top-1);
+break;
+case 8:
+sethvalue(L,gt(thvalue(o)),hvalue(L->top-1));
+break;
+default:
+res=0;
+break;
+}
+if(res)luaC_objbarrier(L,gcvalue(o),hvalue(L->top-1));
+L->top--;
+return res;
+}
+#define adjustresults(L,nres){if(nres==(-1)&&L->top>=L->ci->top)L->ci->top=L->top;}
+#define checkresults(L,na,nr)luai_apicheck(L,(nr)==(-1)||(L->ci->top-L->top>=(nr)-(na)))
+static void lua_call(lua_State*L,int nargs,int nresults){
+StkId func;
+api_checknelems(L,nargs+1);
+checkresults(L,nargs,nresults);
+func=L->top-(nargs+1);
+luaD_call(L,func,nresults);
+adjustresults(L,nresults);
+}
+struct CallS{
+StkId func;
+int nresults;
+};
+static void f_call(lua_State*L,void*ud){
+struct CallS*c=cast(struct CallS*,ud);
+luaD_call(L,c->func,c->nresults);
+}
+static int lua_pcall(lua_State*L,int nargs,int nresults,int errfunc){
+struct CallS c;
+int status;
+ptrdiff_t func;
+api_checknelems(L,nargs+1);
+checkresults(L,nargs,nresults);
+if(errfunc==0)
+func=0;
+else{
+StkId o=index2adr(L,errfunc);
+api_checkvalidindex(L,o);
+func=savestack(L,o);
+}
+c.func=L->top-(nargs+1);
+c.nresults=nresults;
+status=luaD_pcall(L,f_call,&c,savestack(L,c.func),func);
+adjustresults(L,nresults);
+return status;
+}
+static int lua_load(lua_State*L,lua_Reader reader,void*data,
+const char*chunkname){
+ZIO z;
+int status;
+if(!chunkname)chunkname="?";
+luaZ_init(L,&z,reader,data);
+status=luaD_protectedparser(L,&z,chunkname);
+return status;
+}
+static int lua_error(lua_State*L){
+api_checknelems(L,1);
+luaG_errormsg(L);
+return 0;
+}
+static int lua_next(lua_State*L,int idx){
+StkId t;
+int more;
+t=index2adr(L,idx);
+luai_apicheck(L,ttistable(t));
+more=luaH_next(L,hvalue(t),L->top-1);
+if(more){
+api_incr_top(L);
+}
+else
+L->top-=1;
+return more;
+}
+static void lua_concat(lua_State*L,int n){
+api_checknelems(L,n);
+if(n>=2){
+luaC_checkGC(L);
+luaV_concat(L,n,cast_int(L->top-L->base)-1);
+L->top-=(n-1);
+}
+else if(n==0){
+setsvalue(L,L->top,luaS_newlstr(L,"",0));
+api_incr_top(L);
+}
+}
+static void*lua_newuserdata(lua_State*L,size_t size){
+Udata*u;
+luaC_checkGC(L);
+u=luaS_newudata(L,size,getcurrenv(L));
+setuvalue(L,L->top,u);
+api_incr_top(L);
+return u+1;
+}
+#define luaL_getn(L,i)((int)lua_objlen(L,i))
+#define luaL_setn(L,i,j)((void)0)
+typedef struct luaL_Reg{
+const char*name;
+lua_CFunction func;
+}luaL_Reg;
+static void luaI_openlib(lua_State*L,const char*libname,
+const luaL_Reg*l,int nup);
+static int luaL_argerror(lua_State*L,int numarg,const char*extramsg);
+static const char* luaL_checklstring(lua_State*L,int numArg,
+size_t*l);
+static const char* luaL_optlstring(lua_State*L,int numArg,
+const char*def,size_t*l);
+static lua_Integer luaL_checkinteger(lua_State*L,int numArg);
+static lua_Integer luaL_optinteger(lua_State*L,int nArg,
+lua_Integer def);
+static int luaL_error(lua_State*L,const char*fmt,...);
+static const char* luaL_findtable(lua_State*L,int idx,
+const char*fname,int szhint);
+#define luaL_argcheck(L,cond,numarg,extramsg)((void)((cond)||luaL_argerror(L,(numarg),(extramsg))))
+#define luaL_checkstring(L,n)(luaL_checklstring(L,(n),NULL))
+#define luaL_optstring(L,n,d)(luaL_optlstring(L,(n),(d),NULL))
+#define luaL_checkint(L,n)((int)luaL_checkinteger(L,(n)))
+#define luaL_optint(L,n,d)((int)luaL_optinteger(L,(n),(d)))
+#define luaL_typename(L,i)lua_typename(L,lua_type(L,(i)))
+#define luaL_getmetatable(L,n)(lua_getfield(L,(-10000),(n)))
+#define luaL_opt(L,f,n,d)(lua_isnoneornil(L,(n))?(d):f(L,(n)))
+typedef struct luaL_Buffer{
+char*p;
+int lvl;
+lua_State*L;
+char buffer[BUFSIZ];
+}luaL_Buffer;
+#define luaL_addchar(B,c)((void)((B)->p<((B)->buffer+BUFSIZ)||luaL_prepbuffer(B)),(*(B)->p++=(char)(c)))
+#define luaL_addsize(B,n)((B)->p+=(n))
+static char* luaL_prepbuffer(luaL_Buffer*B);
+static int luaL_argerror(lua_State*L,int narg,const char*extramsg){
+lua_Debug ar;
+if(!lua_getstack(L,0,&ar))
+return luaL_error(L,"bad argument #%d (%s)",narg,extramsg);
+lua_getinfo(L,"n",&ar);
+if(strcmp(ar.namewhat,"method")==0){
+narg--;
+if(narg==0)
+return luaL_error(L,"calling "LUA_QL("%s")" on bad self (%s)",
+ar.name,extramsg);
+}
+if(ar.name==NULL)
+ar.name="?";
+return luaL_error(L,"bad argument #%d to "LUA_QL("%s")" (%s)",
+narg,ar.name,extramsg);
+}
+static int luaL_typerror(lua_State*L,int narg,const char*tname){
+const char*msg=lua_pushfstring(L,"%s expected, got %s",
+tname,luaL_typename(L,narg));
+return luaL_argerror(L,narg,msg);
+}
+static void tag_error(lua_State*L,int narg,int tag){
+luaL_typerror(L,narg,lua_typename(L,tag));
+}
+static void luaL_where(lua_State*L,int level){
+lua_Debug ar;
+if(lua_getstack(L,level,&ar)){
+lua_getinfo(L,"Sl",&ar);
+if(ar.currentline>0){
+lua_pushfstring(L,"%s:%d: ",ar.short_src,ar.currentline);
+return;
+}
+}
+lua_pushliteral(L,"");
+}
+static int luaL_error(lua_State*L,const char*fmt,...){
+va_list argp;
+va_start(argp,fmt);
+luaL_where(L,1);
+lua_pushvfstring(L,fmt,argp);
+va_end(argp);
+lua_concat(L,2);
+return lua_error(L);
+}
+static int luaL_newmetatable(lua_State*L,const char*tname){
+lua_getfield(L,(-10000),tname);
+if(!lua_isnil(L,-1))
+return 0;
+lua_pop(L,1);
+lua_newtable(L);
+lua_pushvalue(L,-1);
+lua_setfield(L,(-10000),tname);
+return 1;
+}
+static void*luaL_checkudata(lua_State*L,int ud,const char*tname){
+void*p=lua_touserdata(L,ud);
+if(p!=NULL){
+if(lua_getmetatable(L,ud)){
+lua_getfield(L,(-10000),tname);
+if(lua_rawequal(L,-1,-2)){
+lua_pop(L,2);
+return p;
+}
+}
+}
+luaL_typerror(L,ud,tname);
+return NULL;
+}
+static void luaL_checkstack(lua_State*L,int space,const char*mes){
+if(!lua_checkstack(L,space))
+luaL_error(L,"stack overflow (%s)",mes);
+}
+static void luaL_checktype(lua_State*L,int narg,int t){
+if(lua_type(L,narg)!=t)
+tag_error(L,narg,t);
+}
+static void luaL_checkany(lua_State*L,int narg){
+if(lua_type(L,narg)==(-1))
+luaL_argerror(L,narg,"value expected");
+}
+static const char*luaL_checklstring(lua_State*L,int narg,size_t*len){
+const char*s=lua_tolstring(L,narg,len);
+if(!s)tag_error(L,narg,4);
+return s;
+}
+static const char*luaL_optlstring(lua_State*L,int narg,
+const char*def,size_t*len){
+if(lua_isnoneornil(L,narg)){
+if(len)
+*len=(def?strlen(def):0);
+return def;
+}
+else return luaL_checklstring(L,narg,len);
+}
+static lua_Number luaL_checknumber(lua_State*L,int narg){
+lua_Number d=lua_tonumber(L,narg);
+if(d==0&&!lua_isnumber(L,narg))
+tag_error(L,narg,3);
+return d;
+}
+static lua_Integer luaL_checkinteger(lua_State*L,int narg){
+lua_Integer d=lua_tointeger(L,narg);
+if(d==0&&!lua_isnumber(L,narg))
+tag_error(L,narg,3);
+return d;
+}
+static lua_Integer luaL_optinteger(lua_State*L,int narg,
+lua_Integer def){
+return luaL_opt(L,luaL_checkinteger,narg,def);
+}
+static int luaL_getmetafield(lua_State*L,int obj,const char*event){
+if(!lua_getmetatable(L,obj))
+return 0;
+lua_pushstring(L,event);
+lua_rawget(L,-2);
+if(lua_isnil(L,-1)){
+lua_pop(L,2);
+return 0;
+}
+else{
+lua_remove(L,-2);
+return 1;
+}
+}
+static void luaL_register(lua_State*L,const char*libname,
+const luaL_Reg*l){
+luaI_openlib(L,libname,l,0);
+}
+static int libsize(const luaL_Reg*l){
+int size=0;
+for(;l->name;l++)size++;
+return size;
+}
+static void luaI_openlib(lua_State*L,const char*libname,
+const luaL_Reg*l,int nup){
+if(libname){
+int size=libsize(l);
+luaL_findtable(L,(-10000),"_LOADED",1);
+lua_getfield(L,-1,libname);
+if(!lua_istable(L,-1)){
+lua_pop(L,1);
+if(luaL_findtable(L,(-10002),libname,size)!=NULL)
+luaL_error(L,"name conflict for module "LUA_QL("%s"),libname);
+lua_pushvalue(L,-1);
+lua_setfield(L,-3,libname);
+}
+lua_remove(L,-2);
+lua_insert(L,-(nup+1));
+}
+for(;l->name;l++){
+int i;
+for(i=0;i<nup;i++)
+lua_pushvalue(L,-nup);
+lua_pushcclosure(L,l->func,nup);
+lua_setfield(L,-(nup+2),l->name);
+}
+lua_pop(L,nup);
+}
+static const char*luaL_findtable(lua_State*L,int idx,
+const char*fname,int szhint){
+const char*e;
+lua_pushvalue(L,idx);
+do{
+e=strchr(fname,'.');
+if(e==NULL)e=fname+strlen(fname);
+lua_pushlstring(L,fname,e-fname);
+lua_rawget(L,-2);
+if(lua_isnil(L,-1)){
+lua_pop(L,1);
+lua_createtable(L,0,(*e=='.'?1:szhint));
+lua_pushlstring(L,fname,e-fname);
+lua_pushvalue(L,-2);
+lua_settable(L,-4);
+}
+else if(!lua_istable(L,-1)){
+lua_pop(L,2);
+return fname;
+}
+lua_remove(L,-2);
+fname=e+1;
+}while(*e=='.');
+return NULL;
+}
+#define bufflen(B)((B)->p-(B)->buffer)
+#define bufffree(B)((size_t)(BUFSIZ-bufflen(B)))
+static int emptybuffer(luaL_Buffer*B){
+size_t l=bufflen(B);
+if(l==0)return 0;
+else{
+lua_pushlstring(B->L,B->buffer,l);
+B->p=B->buffer;
+B->lvl++;
+return 1;
+}
+}
+static void adjuststack(luaL_Buffer*B){
+if(B->lvl>1){
+lua_State*L=B->L;
+int toget=1;
+size_t toplen=lua_strlen(L,-1);
+do{
+size_t l=lua_strlen(L,-(toget+1));
+if(B->lvl-toget+1>=(20/2)||toplen>l){
+toplen+=l;
+toget++;
+}
+else break;
+}while(toget<B->lvl);
+lua_concat(L,toget);
+B->lvl=B->lvl-toget+1;
+}
+}
+static char*luaL_prepbuffer(luaL_Buffer*B){
+if(emptybuffer(B))
+adjuststack(B);
+return B->buffer;
+}
+static void luaL_addlstring(luaL_Buffer*B,const char*s,size_t l){
+while(l--)
+luaL_addchar(B,*s++);
+}
+static void luaL_pushresult(luaL_Buffer*B){
+emptybuffer(B);
+lua_concat(B->L,B->lvl);
+B->lvl=1;
+}
+static void luaL_addvalue(luaL_Buffer*B){
+lua_State*L=B->L;
+size_t vl;
+const char*s=lua_tolstring(L,-1,&vl);
+if(vl<=bufffree(B)){
+memcpy(B->p,s,vl);
+B->p+=vl;
+lua_pop(L,1);
+}
+else{
+if(emptybuffer(B))
+lua_insert(L,-2);
+B->lvl++;
+adjuststack(B);
+}
+}
+static void luaL_buffinit(lua_State*L,luaL_Buffer*B){
+B->L=L;
+B->p=B->buffer;
+B->lvl=0;
+}
+typedef struct LoadF{
+int extraline;
+FILE*f;
+char buff[BUFSIZ];
+}LoadF;
+static const char*getF(lua_State*L,void*ud,size_t*size){
+LoadF*lf=(LoadF*)ud;
+(void)L;
+if(lf->extraline){
+lf->extraline=0;
+*size=1;
+return"\n";
+}
+if(feof(lf->f))return NULL;
+*size=fread(lf->buff,1,sizeof(lf->buff),lf->f);
+return(*size>0)?lf->buff:NULL;
+}
+static int errfile(lua_State*L,const char*what,int fnameindex){
+const char*serr=strerror(errno);
+const char*filename=lua_tostring(L,fnameindex)+1;
+lua_pushfstring(L,"cannot %s %s: %s",what,filename,serr);
+lua_remove(L,fnameindex);
+return(5+1);
+}
+static int luaL_loadfile(lua_State*L,const char*filename){
+LoadF lf;
+int status,readstatus;
+int c;
+int fnameindex=lua_gettop(L)+1;
+lf.extraline=0;
+if(filename==NULL){
+lua_pushliteral(L,"=stdin");
+lf.f=stdin;
+}
+else{
+lua_pushfstring(L,"@%s",filename);
+lf.f=fopen(filename,"r");
+if(lf.f==NULL)return errfile(L,"open",fnameindex);
+}
+c=getc(lf.f);
+if(c=='#'){
+lf.extraline=1;
+while((c=getc(lf.f))!=EOF&&c!='\n');
+if(c=='\n')c=getc(lf.f);
+}
+if(c=="\033Lua"[0]&&filename){
+lf.f=freopen(filename,"rb",lf.f);
+if(lf.f==NULL)return errfile(L,"reopen",fnameindex);
+while((c=getc(lf.f))!=EOF&&c!="\033Lua"[0]);
+lf.extraline=0;
+}
+ungetc(c,lf.f);
+status=lua_load(L,getF,&lf,lua_tostring(L,-1));
+readstatus=ferror(lf.f);
+if(filename)fclose(lf.f);
+if(readstatus){
+lua_settop(L,fnameindex);
+return errfile(L,"read",fnameindex);
+}
+lua_remove(L,fnameindex);
+return status;
+}
+typedef struct LoadS{
+const char*s;
+size_t size;
+}LoadS;
+static const char*getS(lua_State*L,void*ud,size_t*size){
+LoadS*ls=(LoadS*)ud;
+(void)L;
+if(ls->size==0)return NULL;
+*size=ls->size;
+ls->size=0;
+return ls->s;
+}
+static int luaL_loadbuffer(lua_State*L,const char*buff,size_t size,
+const char*name){
+LoadS ls;
+ls.s=buff;
+ls.size=size;
+return lua_load(L,getS,&ls,name);
+}
+static void*l_alloc(void*ud,void*ptr,size_t osize,size_t nsize){
+(void)ud;
+(void)osize;
+if(nsize==0){
+free(ptr);
+return NULL;
+}
+else
+return realloc(ptr,nsize);
+}
+static int panic(lua_State*L){
+(void)L;
+fprintf(stderr,"PANIC: unprotected error in call to Lua API (%s)\n",
+lua_tostring(L,-1));
+return 0;
+}
+static lua_State*luaL_newstate(void){
+lua_State*L=lua_newstate(l_alloc,NULL);
+if(L)lua_atpanic(L,&panic);
+return L;
+}
+static int luaB_tonumber(lua_State*L){
+int base=luaL_optint(L,2,10);
+if(base==10){
+luaL_checkany(L,1);
+if(lua_isnumber(L,1)){
+lua_pushnumber(L,lua_tonumber(L,1));
+return 1;
+}
+}
+else{
+const char*s1=luaL_checkstring(L,1);
+char*s2;
+unsigned long n;
+luaL_argcheck(L,2<=base&&base<=36,2,"base out of range");
+n=strtoul(s1,&s2,base);
+if(s1!=s2){
+while(isspace((unsigned char)(*s2)))s2++;
+if(*s2=='\0'){
+lua_pushnumber(L,(lua_Number)n);
+return 1;
+}
+}
+}
+lua_pushnil(L);
+return 1;
+}
+static int luaB_error(lua_State*L){
+int level=luaL_optint(L,2,1);
+lua_settop(L,1);
+if(lua_isstring(L,1)&&level>0){
+luaL_where(L,level);
+lua_pushvalue(L,1);
+lua_concat(L,2);
+}
+return lua_error(L);
+}
+static int luaB_setmetatable(lua_State*L){
+int t=lua_type(L,2);
+luaL_checktype(L,1,5);
+luaL_argcheck(L,t==0||t==5,2,
+"nil or table expected");
+if(luaL_getmetafield(L,1,"__metatable"))
+luaL_error(L,"cannot change a protected metatable");
+lua_settop(L,2);
+lua_setmetatable(L,1);
+return 1;
+}
+static void getfunc(lua_State*L,int opt){
+if(lua_isfunction(L,1))lua_pushvalue(L,1);
+else{
+lua_Debug ar;
+int level=opt?luaL_optint(L,1,1):luaL_checkint(L,1);
+luaL_argcheck(L,level>=0,1,"level must be non-negative");
+if(lua_getstack(L,level,&ar)==0)
+luaL_argerror(L,1,"invalid level");
+lua_getinfo(L,"f",&ar);
+if(lua_isnil(L,-1))
+luaL_error(L,"no function environment for tail call at level %d",
+level);
+}
+}
+static int luaB_setfenv(lua_State*L){
+luaL_checktype(L,2,5);
+getfunc(L,0);
+lua_pushvalue(L,2);
+if(lua_isnumber(L,1)&&lua_tonumber(L,1)==0){
+lua_pushthread(L);
+lua_insert(L,-2);
+lua_setfenv(L,-2);
+return 0;
+}
+else if(lua_iscfunction(L,-2)||lua_setfenv(L,-2)==0)
+luaL_error(L,
+LUA_QL("setfenv")" cannot change environment of given object");
+return 1;
+}
+static int luaB_rawget(lua_State*L){
+luaL_checktype(L,1,5);
+luaL_checkany(L,2);
+lua_settop(L,2);
+lua_rawget(L,1);
+return 1;
+}
+static int luaB_type(lua_State*L){
+luaL_checkany(L,1);
+lua_pushstring(L,luaL_typename(L,1));
+return 1;
+}
+static int luaB_next(lua_State*L){
+luaL_checktype(L,1,5);
+lua_settop(L,2);
+if(lua_next(L,1))
+return 2;
+else{
+lua_pushnil(L);
+return 1;
+}
+}
+static int luaB_pairs(lua_State*L){
+luaL_checktype(L,1,5);
+lua_pushvalue(L,lua_upvalueindex(1));
+lua_pushvalue(L,1);
+lua_pushnil(L);
+return 3;
+}
+static int ipairsaux(lua_State*L){
+int i=luaL_checkint(L,2);
+luaL_checktype(L,1,5);
+i++;
+lua_pushinteger(L,i);
+lua_rawgeti(L,1,i);
+return(lua_isnil(L,-1))?0:2;
+}
+static int luaB_ipairs(lua_State*L){
+luaL_checktype(L,1,5);
+lua_pushvalue(L,lua_upvalueindex(1));
+lua_pushvalue(L,1);
+lua_pushinteger(L,0);
+return 3;
+}
+static int load_aux(lua_State*L,int status){
+if(status==0)
+return 1;
+else{
+lua_pushnil(L);
+lua_insert(L,-2);
+return 2;
+}
+}
+static int luaB_loadstring(lua_State*L){
+size_t l;
+const char*s=luaL_checklstring(L,1,&l);
+const char*chunkname=luaL_optstring(L,2,s);
+return load_aux(L,luaL_loadbuffer(L,s,l,chunkname));
+}
+static int luaB_loadfile(lua_State*L){
+const char*fname=luaL_optstring(L,1,NULL);
+return load_aux(L,luaL_loadfile(L,fname));
+}
+static int luaB_assert(lua_State*L){
+luaL_checkany(L,1);
+if(!lua_toboolean(L,1))
+return luaL_error(L,"%s",luaL_optstring(L,2,"assertion failed!"));
+return lua_gettop(L);
+}
+static int luaB_unpack(lua_State*L){
+int i,e,n;
+luaL_checktype(L,1,5);
+i=luaL_optint(L,2,1);
+e=luaL_opt(L,luaL_checkint,3,luaL_getn(L,1));
+if(i>e)return 0;
+n=e-i+1;
+if(n<=0||!lua_checkstack(L,n))
+return luaL_error(L,"too many results to unpack");
+lua_rawgeti(L,1,i);
+while(i++<e)
+lua_rawgeti(L,1,i);
+return n;
+}
+static int luaB_pcall(lua_State*L){
+int status;
+luaL_checkany(L,1);
+status=lua_pcall(L,lua_gettop(L)-1,(-1),0);
+lua_pushboolean(L,(status==0));
+lua_insert(L,1);
+return lua_gettop(L);
+}
+static int luaB_newproxy(lua_State*L){
+lua_settop(L,1);
+lua_newuserdata(L,0);
+if(lua_toboolean(L,1)==0)
+return 1;
+else if(lua_isboolean(L,1)){
+lua_newtable(L);
+lua_pushvalue(L,-1);
+lua_pushboolean(L,1);
+lua_rawset(L,lua_upvalueindex(1));
+}
+else{
+int validproxy=0;
+if(lua_getmetatable(L,1)){
+lua_rawget(L,lua_upvalueindex(1));
+validproxy=lua_toboolean(L,-1);
+lua_pop(L,1);
+}
+luaL_argcheck(L,validproxy,1,"boolean or proxy expected");
+lua_getmetatable(L,1);
+}
+lua_setmetatable(L,2);
+return 1;
+}
+static const luaL_Reg base_funcs[]={
+{"assert",luaB_assert},
+{"error",luaB_error},
+{"loadfile",luaB_loadfile},
+{"loadstring",luaB_loadstring},
+{"next",luaB_next},
+{"pcall",luaB_pcall},
+{"rawget",luaB_rawget},
+{"setfenv",luaB_setfenv},
+{"setmetatable",luaB_setmetatable},
+{"tonumber",luaB_tonumber},
+{"type",luaB_type},
+{"unpack",luaB_unpack},
+{NULL,NULL}
+};
+static void auxopen(lua_State*L,const char*name,
+lua_CFunction f,lua_CFunction u){
+lua_pushcfunction(L,u);
+lua_pushcclosure(L,f,1);
+lua_setfield(L,-2,name);
+}
+static void base_open(lua_State*L){
+lua_pushvalue(L,(-10002));
+lua_setglobal(L,"_G");
+luaL_register(L,"_G",base_funcs);
+lua_pushliteral(L,"Lua 5.1");
+lua_setglobal(L,"_VERSION");
+auxopen(L,"ipairs",luaB_ipairs,ipairsaux);
+auxopen(L,"pairs",luaB_pairs,luaB_next);
+lua_createtable(L,0,1);
+lua_pushvalue(L,-1);
+lua_setmetatable(L,-2);
+lua_pushliteral(L,"kv");
+lua_setfield(L,-2,"__mode");
+lua_pushcclosure(L,luaB_newproxy,1);
+lua_setglobal(L,"newproxy");
+}
+static int luaopen_base(lua_State*L){
+base_open(L);
+return 1;
+}
+#define aux_getn(L,n)(luaL_checktype(L,n,5),luaL_getn(L,n))
+static int tinsert(lua_State*L){
+int e=aux_getn(L,1)+1;
+int pos;
+switch(lua_gettop(L)){
+case 2:{
+pos=e;
+break;
+}
+case 3:{
+int i;
+pos=luaL_checkint(L,2);
+if(pos>e)e=pos;
+for(i=e;i>pos;i--){
+lua_rawgeti(L,1,i-1);
+lua_rawseti(L,1,i);
+}
+break;
+}
+default:{
+return luaL_error(L,"wrong number of arguments to "LUA_QL("insert"));
+}
+}
+luaL_setn(L,1,e);
+lua_rawseti(L,1,pos);
+return 0;
+}
+static int tremove(lua_State*L){
+int e=aux_getn(L,1);
+int pos=luaL_optint(L,2,e);
+if(!(1<=pos&&pos<=e))
+return 0;
+luaL_setn(L,1,e-1);
+lua_rawgeti(L,1,pos);
+for(;pos<e;pos++){
+lua_rawgeti(L,1,pos+1);
+lua_rawseti(L,1,pos);
+}
+lua_pushnil(L);
+lua_rawseti(L,1,e);
+return 1;
+}
+static void addfield(lua_State*L,luaL_Buffer*b,int i){
+lua_rawgeti(L,1,i);
+if(!lua_isstring(L,-1))
+luaL_error(L,"invalid value (%s) at index %d in table for "
+LUA_QL("concat"),luaL_typename(L,-1),i);
+luaL_addvalue(b);
+}
+static int tconcat(lua_State*L){
+luaL_Buffer b;
+size_t lsep;
+int i,last;
+const char*sep=luaL_optlstring(L,2,"",&lsep);
+luaL_checktype(L,1,5);
+i=luaL_optint(L,3,1);
+last=luaL_opt(L,luaL_checkint,4,luaL_getn(L,1));
+luaL_buffinit(L,&b);
+for(;i<last;i++){
+addfield(L,&b,i);
+luaL_addlstring(&b,sep,lsep);
+}
+if(i==last)
+addfield(L,&b,i);
+luaL_pushresult(&b);
+return 1;
+}
+static void set2(lua_State*L,int i,int j){
+lua_rawseti(L,1,i);
+lua_rawseti(L,1,j);
+}
+static int sort_comp(lua_State*L,int a,int b){
+if(!lua_isnil(L,2)){
+int res;
+lua_pushvalue(L,2);
+lua_pushvalue(L,a-1);
+lua_pushvalue(L,b-2);
+lua_call(L,2,1);
+res=lua_toboolean(L,-1);
+lua_pop(L,1);
+return res;
+}
+else
+return lua_lessthan(L,a,b);
+}
+static void auxsort(lua_State*L,int l,int u){
+while(l<u){
+int i,j;
+lua_rawgeti(L,1,l);
+lua_rawgeti(L,1,u);
+if(sort_comp(L,-1,-2))
+set2(L,l,u);
+else
+lua_pop(L,2);
+if(u-l==1)break;
+i=(l+u)/2;
+lua_rawgeti(L,1,i);
+lua_rawgeti(L,1,l);
+if(sort_comp(L,-2,-1))
+set2(L,i,l);
+else{
+lua_pop(L,1);
+lua_rawgeti(L,1,u);
+if(sort_comp(L,-1,-2))
+set2(L,i,u);
+else
+lua_pop(L,2);
+}
+if(u-l==2)break;
+lua_rawgeti(L,1,i);
+lua_pushvalue(L,-1);
+lua_rawgeti(L,1,u-1);
+set2(L,i,u-1);
+i=l;j=u-1;
+for(;;){
+while(lua_rawgeti(L,1,++i),sort_comp(L,-1,-2)){
+if(i>u)luaL_error(L,"invalid order function for sorting");
+lua_pop(L,1);
+}
+while(lua_rawgeti(L,1,--j),sort_comp(L,-3,-1)){
+if(j<l)luaL_error(L,"invalid order function for sorting");
+lua_pop(L,1);
+}
+if(j<i){
+lua_pop(L,3);
+break;
+}
+set2(L,i,j);
+}
+lua_rawgeti(L,1,u-1);
+lua_rawgeti(L,1,i);
+set2(L,u-1,i);
+if(i-l<u-i){
+j=l;i=i-1;l=i+2;
+}
+else{
+j=i+1;i=u;u=j-2;
+}
+auxsort(L,j,i);
+}
+}
+static int sort(lua_State*L){
+int n=aux_getn(L,1);
+luaL_checkstack(L,40,"");
+if(!lua_isnoneornil(L,2))
+luaL_checktype(L,2,6);
+lua_settop(L,2);
+auxsort(L,1,n);
+return 0;
+}
+static const luaL_Reg tab_funcs[]={
+{"concat",tconcat},
+{"insert",tinsert},
+{"remove",tremove},
+{"sort",sort},
+{NULL,NULL}
+};
+static int luaopen_table(lua_State*L){
+luaL_register(L,"table",tab_funcs);
+return 1;
+}
+static const char*const fnames[]={"input","output"};
+static int pushresult(lua_State*L,int i,const char*filename){
+int en=errno;
+if(i){
+lua_pushboolean(L,1);
+return 1;
+}
+else{
+lua_pushnil(L);
+if(filename)
+lua_pushfstring(L,"%s: %s",filename,strerror(en));
+else
+lua_pushfstring(L,"%s",strerror(en));
+lua_pushinteger(L,en);
+return 3;
+}
+}
+static void fileerror(lua_State*L,int arg,const char*filename){
+lua_pushfstring(L,"%s: %s",filename,strerror(errno));
+luaL_argerror(L,arg,lua_tostring(L,-1));
+}
+#define tofilep(L)((FILE**)luaL_checkudata(L,1,"FILE*"))
+static int io_type(lua_State*L){
+void*ud;
+luaL_checkany(L,1);
+ud=lua_touserdata(L,1);
+lua_getfield(L,(-10000),"FILE*");
+if(ud==NULL||!lua_getmetatable(L,1)||!lua_rawequal(L,-2,-1))
+lua_pushnil(L);
+else if(*((FILE**)ud)==NULL)
+lua_pushliteral(L,"closed file");
+else
+lua_pushliteral(L,"file");
+return 1;
+}
+static FILE*tofile(lua_State*L){
+FILE**f=tofilep(L);
+if(*f==NULL)
+luaL_error(L,"attempt to use a closed file");
+return*f;
+}
+static FILE**newfile(lua_State*L){
+FILE**pf=(FILE**)lua_newuserdata(L,sizeof(FILE*));
+*pf=NULL;
+luaL_getmetatable(L,"FILE*");
+lua_setmetatable(L,-2);
+return pf;
+}
+static int io_noclose(lua_State*L){
+lua_pushnil(L);
+lua_pushliteral(L,"cannot close standard file");
+return 2;
+}
+static int io_pclose(lua_State*L){
+FILE**p=tofilep(L);
+int ok=lua_pclose(L,*p);
+*p=NULL;
+return pushresult(L,ok,NULL);
+}
+static int io_fclose(lua_State*L){
+FILE**p=tofilep(L);
+int ok=(fclose(*p)==0);
+*p=NULL;
+return pushresult(L,ok,NULL);
+}
+static int aux_close(lua_State*L){
+lua_getfenv(L,1);
+lua_getfield(L,-1,"__close");
+return(lua_tocfunction(L,-1))(L);
+}
+static int io_close(lua_State*L){
+if(lua_isnone(L,1))
+lua_rawgeti(L,(-10001),2);
+tofile(L);
+return aux_close(L);
+}
+static int io_gc(lua_State*L){
+FILE*f=*tofilep(L);
+if(f!=NULL)
+aux_close(L);
+return 0;
+}
+static int io_open(lua_State*L){
+const char*filename=luaL_checkstring(L,1);
+const char*mode=luaL_optstring(L,2,"r");
+FILE**pf=newfile(L);
+*pf=fopen(filename,mode);
+return(*pf==NULL)?pushresult(L,0,filename):1;
+}
+static FILE*getiofile(lua_State*L,int findex){
+FILE*f;
+lua_rawgeti(L,(-10001),findex);
+f=*(FILE**)lua_touserdata(L,-1);
+if(f==NULL)
+luaL_error(L,"standard %s file is closed",fnames[findex-1]);
+return f;
+}
+static int g_iofile(lua_State*L,int f,const char*mode){
+if(!lua_isnoneornil(L,1)){
+const char*filename=lua_tostring(L,1);
+if(filename){
+FILE**pf=newfile(L);
+*pf=fopen(filename,mode);
+if(*pf==NULL)
+fileerror(L,1,filename);
+}
+else{
+tofile(L);
+lua_pushvalue(L,1);
+}
+lua_rawseti(L,(-10001),f);
+}
+lua_rawgeti(L,(-10001),f);
+return 1;
+}
+static int io_input(lua_State*L){
+return g_iofile(L,1,"r");
+}
+static int io_output(lua_State*L){
+return g_iofile(L,2,"w");
+}
+static int io_readline(lua_State*L);
+static void aux_lines(lua_State*L,int idx,int toclose){
+lua_pushvalue(L,idx);
+lua_pushboolean(L,toclose);
+lua_pushcclosure(L,io_readline,2);
+}
+static int f_lines(lua_State*L){
+tofile(L);
+aux_lines(L,1,0);
+return 1;
+}
+static int io_lines(lua_State*L){
+if(lua_isnoneornil(L,1)){
+lua_rawgeti(L,(-10001),1);
+return f_lines(L);
+}
+else{
+const char*filename=luaL_checkstring(L,1);
+FILE**pf=newfile(L);
+*pf=fopen(filename,"r");
+if(*pf==NULL)
+fileerror(L,1,filename);
+aux_lines(L,lua_gettop(L),1);
+return 1;
+}
+}
+static int read_number(lua_State*L,FILE*f){
+lua_Number d;
+if(fscanf(f,"%lf",&d)==1){
+lua_pushnumber(L,d);
+return 1;
+}
+else{
+lua_pushnil(L);
+return 0;
+}
+}
+static int test_eof(lua_State*L,FILE*f){
+int c=getc(f);
+ungetc(c,f);
+lua_pushlstring(L,NULL,0);
+return(c!=EOF);
+}
+static int read_line(lua_State*L,FILE*f){
+luaL_Buffer b;
+luaL_buffinit(L,&b);
+for(;;){
+size_t l;
+char*p=luaL_prepbuffer(&b);
+if(fgets(p,BUFSIZ,f)==NULL){
+luaL_pushresult(&b);
+return(lua_objlen(L,-1)>0);
+}
+l=strlen(p);
+if(l==0||p[l-1]!='\n')
+luaL_addsize(&b,l);
+else{
+luaL_addsize(&b,l-1);
+luaL_pushresult(&b);
+return 1;
+}
+}
+}
+static int read_chars(lua_State*L,FILE*f,size_t n){
+size_t rlen;
+size_t nr;
+luaL_Buffer b;
+luaL_buffinit(L,&b);
+rlen=BUFSIZ;
+do{
+char*p=luaL_prepbuffer(&b);
+if(rlen>n)rlen=n;
+nr=fread(p,sizeof(char),rlen,f);
+luaL_addsize(&b,nr);
+n-=nr;
+}while(n>0&&nr==rlen);
+luaL_pushresult(&b);
+return(n==0||lua_objlen(L,-1)>0);
+}
+static int g_read(lua_State*L,FILE*f,int first){
+int nargs=lua_gettop(L)-1;
+int success;
+int n;
+clearerr(f);
+if(nargs==0){
+success=read_line(L,f);
+n=first+1;
+}
+else{
+luaL_checkstack(L,nargs+20,"too many arguments");
+success=1;
+for(n=first;nargs--&&success;n++){
+if(lua_type(L,n)==3){
+size_t l=(size_t)lua_tointeger(L,n);
+success=(l==0)?test_eof(L,f):read_chars(L,f,l);
+}
+else{
+const char*p=lua_tostring(L,n);
+luaL_argcheck(L,p&&p[0]=='*',n,"invalid option");
+switch(p[1]){
+case'n':
+success=read_number(L,f);
+break;
+case'l':
+success=read_line(L,f);
+break;
+case'a':
+read_chars(L,f,~((size_t)0));
+success=1;
+break;
+default:
+return luaL_argerror(L,n,"invalid format");
+}
+}
+}
+}
+if(ferror(f))
+return pushresult(L,0,NULL);
+if(!success){
+lua_pop(L,1);
+lua_pushnil(L);
+}
+return n-first;
+}
+static int io_read(lua_State*L){
+return g_read(L,getiofile(L,1),1);
+}
+static int f_read(lua_State*L){
+return g_read(L,tofile(L),2);
+}
+static int io_readline(lua_State*L){
+FILE*f=*(FILE**)lua_touserdata(L,lua_upvalueindex(1));
+int success;
+if(f==NULL)
+luaL_error(L,"file is already closed");
+success=read_line(L,f);
+if(ferror(f))
+return luaL_error(L,"%s",strerror(errno));
+if(success)return 1;
+else{
+if(lua_toboolean(L,lua_upvalueindex(2))){
+lua_settop(L,0);
+lua_pushvalue(L,lua_upvalueindex(1));
+aux_close(L);
+}
+return 0;
+}
+}
+static int g_write(lua_State*L,FILE*f,int arg){
+int nargs=lua_gettop(L)-1;
+int status=1;
+for(;nargs--;arg++){
+if(lua_type(L,arg)==3){
+status=status&&
+fprintf(f,"%.14g",lua_tonumber(L,arg))>0;
+}
+else{
+size_t l;
+const char*s=luaL_checklstring(L,arg,&l);
+status=status&&(fwrite(s,sizeof(char),l,f)==l);
+}
+}
+return pushresult(L,status,NULL);
+}
+static int io_write(lua_State*L){
+return g_write(L,getiofile(L,2),1);
+}
+static int f_write(lua_State*L){
+return g_write(L,tofile(L),2);
+}
+static int io_flush(lua_State*L){
+return pushresult(L,fflush(getiofile(L,2))==0,NULL);
+}
+static int f_flush(lua_State*L){
+return pushresult(L,fflush(tofile(L))==0,NULL);
+}
+static const luaL_Reg iolib[]={
+{"close",io_close},
+{"flush",io_flush},
+{"input",io_input},
+{"lines",io_lines},
+{"open",io_open},
+{"output",io_output},
+{"read",io_read},
+{"type",io_type},
+{"write",io_write},
+{NULL,NULL}
+};
+static const luaL_Reg flib[]={
+{"close",io_close},
+{"flush",f_flush},
+{"lines",f_lines},
+{"read",f_read},
+{"write",f_write},
+{"__gc",io_gc},
+{NULL,NULL}
+};
+static void createmeta(lua_State*L){
+luaL_newmetatable(L,"FILE*");
+lua_pushvalue(L,-1);
+lua_setfield(L,-2,"__index");
+luaL_register(L,NULL,flib);
+}
+static void createstdfile(lua_State*L,FILE*f,int k,const char*fname){
+*newfile(L)=f;
+if(k>0){
+lua_pushvalue(L,-1);
+lua_rawseti(L,(-10001),k);
+}
+lua_pushvalue(L,-2);
+lua_setfenv(L,-2);
+lua_setfield(L,-3,fname);
+}
+static void newfenv(lua_State*L,lua_CFunction cls){
+lua_createtable(L,0,1);
+lua_pushcfunction(L,cls);
+lua_setfield(L,-2,"__close");
+}
+static int luaopen_io(lua_State*L){
+createmeta(L);
+newfenv(L,io_fclose);
+lua_replace(L,(-10001));
+luaL_register(L,"io",iolib);
+newfenv(L,io_noclose);
+createstdfile(L,stdin,1,"stdin");
+createstdfile(L,stdout,2,"stdout");
+createstdfile(L,stderr,0,"stderr");
+lua_pop(L,1);
+lua_getfield(L,-1,"popen");
+newfenv(L,io_pclose);
+lua_setfenv(L,-2);
+lua_pop(L,1);
+return 1;
+}
+static int os_pushresult(lua_State*L,int i,const char*filename){
+int en=errno;
+if(i){
+lua_pushboolean(L,1);
+return 1;
+}
+else{
+lua_pushnil(L);
+lua_pushfstring(L,"%s: %s",filename,strerror(en));
+lua_pushinteger(L,en);
+return 3;
+}
+}
+static int os_remove(lua_State*L){
+const char*filename=luaL_checkstring(L,1);
+return os_pushresult(L,remove(filename)==0,filename);
+}
+static int os_exit(lua_State*L){
+exit(luaL_optint(L,1,EXIT_SUCCESS));
+}
+static const luaL_Reg syslib[]={
+{"exit",os_exit},
+{"remove",os_remove},
+{NULL,NULL}
+};
+static int luaopen_os(lua_State*L){
+luaL_register(L,"os",syslib);
+return 1;
+}
+#define uchar(c)((unsigned char)(c))
+static ptrdiff_t posrelat(ptrdiff_t pos,size_t len){
+if(pos<0)pos+=(ptrdiff_t)len+1;
+return(pos>=0)?pos:0;
+}
+static int str_sub(lua_State*L){
+size_t l;
+const char*s=luaL_checklstring(L,1,&l);
+ptrdiff_t start=posrelat(luaL_checkinteger(L,2),l);
+ptrdiff_t end=posrelat(luaL_optinteger(L,3,-1),l);
+if(start<1)start=1;
+if(end>(ptrdiff_t)l)end=(ptrdiff_t)l;
+if(start<=end)
+lua_pushlstring(L,s+start-1,end-start+1);
+else lua_pushliteral(L,"");
+return 1;
+}
+static int str_lower(lua_State*L){
+size_t l;
+size_t i;
+luaL_Buffer b;
+const char*s=luaL_checklstring(L,1,&l);
+luaL_buffinit(L,&b);
+for(i=0;i<l;i++)
+luaL_addchar(&b,tolower(uchar(s[i])));
+luaL_pushresult(&b);
+return 1;
+}
+static int str_upper(lua_State*L){
+size_t l;
+size_t i;
+luaL_Buffer b;
+const char*s=luaL_checklstring(L,1,&l);
+luaL_buffinit(L,&b);
+for(i=0;i<l;i++)
+luaL_addchar(&b,toupper(uchar(s[i])));
+luaL_pushresult(&b);
+return 1;
+}
+static int str_rep(lua_State*L){
+size_t l;
+luaL_Buffer b;
+const char*s=luaL_checklstring(L,1,&l);
+int n=luaL_checkint(L,2);
+luaL_buffinit(L,&b);
+while(n-->0)
+luaL_addlstring(&b,s,l);
+luaL_pushresult(&b);
+return 1;
+}
+static int str_byte(lua_State*L){
+size_t l;
+const char*s=luaL_checklstring(L,1,&l);
+ptrdiff_t posi=posrelat(luaL_optinteger(L,2,1),l);
+ptrdiff_t pose=posrelat(luaL_optinteger(L,3,posi),l);
+int n,i;
+if(posi<=0)posi=1;
+if((size_t)pose>l)pose=l;
+if(posi>pose)return 0;
+n=(int)(pose-posi+1);
+if(posi+n<=pose)
+luaL_error(L,"string slice too long");
+luaL_checkstack(L,n,"string slice too long");
+for(i=0;i<n;i++)
+lua_pushinteger(L,uchar(s[posi+i-1]));
+return n;
+}
+static int str_char(lua_State*L){
+int n=lua_gettop(L);
+int i;
+luaL_Buffer b;
+luaL_buffinit(L,&b);
+for(i=1;i<=n;i++){
+int c=luaL_checkint(L,i);
+luaL_argcheck(L,uchar(c)==c,i,"invalid value");
+luaL_addchar(&b,uchar(c));
+}
+luaL_pushresult(&b);
+return 1;
+}
+typedef struct MatchState{
+const char*src_init;
+const char*src_end;
+lua_State*L;
+int level;
+struct{
+const char*init;
+ptrdiff_t len;
+}capture[32];
+}MatchState;
+static int check_capture(MatchState*ms,int l){
+l-='1';
+if(l<0||l>=ms->level||ms->capture[l].len==(-1))
+return luaL_error(ms->L,"invalid capture index");
+return l;
+}
+static int capture_to_close(MatchState*ms){
+int level=ms->level;
+for(level--;level>=0;level--)
+if(ms->capture[level].len==(-1))return level;
+return luaL_error(ms->L,"invalid pattern capture");
+}
+static const char*classend(MatchState*ms,const char*p){
+switch(*p++){
+case'%':{
+if(*p=='\0')
+luaL_error(ms->L,"malformed pattern (ends with "LUA_QL("%%")")");
+return p+1;
+}
+case'[':{
+if(*p=='^')p++;
+do{
+if(*p=='\0')
+luaL_error(ms->L,"malformed pattern (missing "LUA_QL("]")")");
+if(*(p++)=='%'&&*p!='\0')
+p++;
+}while(*p!=']');
+return p+1;
+}
+default:{
+return p;
+}
+}
+}
+static int match_class(int c,int cl){
+int res;
+switch(tolower(cl)){
+case'a':res=isalpha(c);break;
+case'c':res=iscntrl(c);break;
+case'd':res=isdigit(c);break;
+case'l':res=islower(c);break;
+case'p':res=ispunct(c);break;
+case's':res=isspace(c);break;
+case'u':res=isupper(c);break;
+case'w':res=isalnum(c);break;
+case'x':res=isxdigit(c);break;
+case'z':res=(c==0);break;
+default:return(cl==c);
+}
+return(islower(cl)?res:!res);
+}
+static int matchbracketclass(int c,const char*p,const char*ec){
+int sig=1;
+if(*(p+1)=='^'){
+sig=0;
+p++;
+}
+while(++p<ec){
+if(*p=='%'){
+p++;
+if(match_class(c,uchar(*p)))
+return sig;
+}
+else if((*(p+1)=='-')&&(p+2<ec)){
+p+=2;
+if(uchar(*(p-2))<=c&&c<=uchar(*p))
+return sig;
+}
+else if(uchar(*p)==c)return sig;
+}
+return!sig;
+}
+static int singlematch(int c,const char*p,const char*ep){
+switch(*p){
+case'.':return 1;
+case'%':return match_class(c,uchar(*(p+1)));
+case'[':return matchbracketclass(c,p,ep-1);
+default:return(uchar(*p)==c);
+}
+}
+static const char*match(MatchState*ms,const char*s,const char*p);
+static const char*matchbalance(MatchState*ms,const char*s,
+const char*p){
+if(*p==0||*(p+1)==0)
+luaL_error(ms->L,"unbalanced pattern");
+if(*s!=*p)return NULL;
+else{
+int b=*p;
+int e=*(p+1);
+int cont=1;
+while(++s<ms->src_end){
+if(*s==e){
+if(--cont==0)return s+1;
+}
+else if(*s==b)cont++;
+}
+}
+return NULL;
+}
+static const char*max_expand(MatchState*ms,const char*s,
+const char*p,const char*ep){
+ptrdiff_t i=0;
+while((s+i)<ms->src_end&&singlematch(uchar(*(s+i)),p,ep))
+i++;
+while(i>=0){
+const char*res=match(ms,(s+i),ep+1);
+if(res)return res;
+i--;
+}
+return NULL;
+}
+static const char*min_expand(MatchState*ms,const char*s,
+const char*p,const char*ep){
+for(;;){
+const char*res=match(ms,s,ep+1);
+if(res!=NULL)
+return res;
+else if(s<ms->src_end&&singlematch(uchar(*s),p,ep))
+s++;
+else return NULL;
+}
+}
+static const char*start_capture(MatchState*ms,const char*s,
+const char*p,int what){
+const char*res;
+int level=ms->level;
+if(level>=32)luaL_error(ms->L,"too many captures");
+ms->capture[level].init=s;
+ms->capture[level].len=what;
+ms->level=level+1;
+if((res=match(ms,s,p))==NULL)
+ms->level--;
+return res;
+}
+static const char*end_capture(MatchState*ms,const char*s,
+const char*p){
+int l=capture_to_close(ms);
+const char*res;
+ms->capture[l].len=s-ms->capture[l].init;
+if((res=match(ms,s,p))==NULL)
+ms->capture[l].len=(-1);
+return res;
+}
+static const char*match_capture(MatchState*ms,const char*s,int l){
+size_t len;
+l=check_capture(ms,l);
+len=ms->capture[l].len;
+if((size_t)(ms->src_end-s)>=len&&
+memcmp(ms->capture[l].init,s,len)==0)
+return s+len;
+else return NULL;
+}
+static const char*match(MatchState*ms,const char*s,const char*p){
+init:
+switch(*p){
+case'(':{
+if(*(p+1)==')')
+return start_capture(ms,s,p+2,(-2));
+else
+return start_capture(ms,s,p+1,(-1));
+}
+case')':{
+return end_capture(ms,s,p+1);
+}
+case'%':{
+switch(*(p+1)){
+case'b':{
+s=matchbalance(ms,s,p+2);
+if(s==NULL)return NULL;
+p+=4;goto init;
+}
+case'f':{
+const char*ep;char previous;
+p+=2;
+if(*p!='[')
+luaL_error(ms->L,"missing "LUA_QL("[")" after "
+LUA_QL("%%f")" in pattern");
+ep=classend(ms,p);
+previous=(s==ms->src_init)?'\0':*(s-1);
+if(matchbracketclass(uchar(previous),p,ep-1)||
+!matchbracketclass(uchar(*s),p,ep-1))return NULL;
+p=ep;goto init;
+}
+default:{
+if(isdigit(uchar(*(p+1)))){
+s=match_capture(ms,s,uchar(*(p+1)));
+if(s==NULL)return NULL;
+p+=2;goto init;
+}
+goto dflt;
+}
+}
+}
+case'\0':{
+return s;
+}
+case'$':{
+if(*(p+1)=='\0')
+return(s==ms->src_end)?s:NULL;
+else goto dflt;
+}
+default:dflt:{
+const char*ep=classend(ms,p);
+int m=s<ms->src_end&&singlematch(uchar(*s),p,ep);
+switch(*ep){
+case'?':{
+const char*res;
+if(m&&((res=match(ms,s+1,ep+1))!=NULL))
+return res;
+p=ep+1;goto init;
+}
+case'*':{
+return max_expand(ms,s,p,ep);
+}
+case'+':{
+return(m?max_expand(ms,s+1,p,ep):NULL);
+}
+case'-':{
+return min_expand(ms,s,p,ep);
+}
+default:{
+if(!m)return NULL;
+s++;p=ep;goto init;
+}
+}
+}
+}
+}
+static const char*lmemfind(const char*s1,size_t l1,
+const char*s2,size_t l2){
+if(l2==0)return s1;
+else if(l2>l1)return NULL;
+else{
+const char*init;
+l2--;
+l1=l1-l2;
+while(l1>0&&(init=(const char*)memchr(s1,*s2,l1))!=NULL){
+init++;
+if(memcmp(init,s2+1,l2)==0)
+return init-1;
+else{
+l1-=init-s1;
+s1=init;
+}
+}
+return NULL;
+}
+}
+static void push_onecapture(MatchState*ms,int i,const char*s,
+const char*e){
+if(i>=ms->level){
+if(i==0)
+lua_pushlstring(ms->L,s,e-s);
+else
+luaL_error(ms->L,"invalid capture index");
+}
+else{
+ptrdiff_t l=ms->capture[i].len;
+if(l==(-1))luaL_error(ms->L,"unfinished capture");
+if(l==(-2))
+lua_pushinteger(ms->L,ms->capture[i].init-ms->src_init+1);
+else
+lua_pushlstring(ms->L,ms->capture[i].init,l);
+}
+}
+static int push_captures(MatchState*ms,const char*s,const char*e){
+int i;
+int nlevels=(ms->level==0&&s)?1:ms->level;
+luaL_checkstack(ms->L,nlevels,"too many captures");
+for(i=0;i<nlevels;i++)
+push_onecapture(ms,i,s,e);
+return nlevels;
+}
+static int str_find_aux(lua_State*L,int find){
+size_t l1,l2;
+const char*s=luaL_checklstring(L,1,&l1);
+const char*p=luaL_checklstring(L,2,&l2);
+ptrdiff_t init=posrelat(luaL_optinteger(L,3,1),l1)-1;
+if(init<0)init=0;
+else if((size_t)(init)>l1)init=(ptrdiff_t)l1;
+if(find&&(lua_toboolean(L,4)||
+strpbrk(p,"^$*+?.([%-")==NULL)){
+const char*s2=lmemfind(s+init,l1-init,p,l2);
+if(s2){
+lua_pushinteger(L,s2-s+1);
+lua_pushinteger(L,s2-s+l2);
+return 2;
+}
+}
+else{
+MatchState ms;
+int anchor=(*p=='^')?(p++,1):0;
+const char*s1=s+init;
+ms.L=L;
+ms.src_init=s;
+ms.src_end=s+l1;
+do{
+const char*res;
+ms.level=0;
+if((res=match(&ms,s1,p))!=NULL){
+if(find){
+lua_pushinteger(L,s1-s+1);
+lua_pushinteger(L,res-s);
+return push_captures(&ms,NULL,0)+2;
+}
+else
+return push_captures(&ms,s1,res);
+}
+}while(s1++<ms.src_end&&!anchor);
+}
+lua_pushnil(L);
+return 1;
+}
+static int str_find(lua_State*L){
+return str_find_aux(L,1);
+}
+static int str_match(lua_State*L){
+return str_find_aux(L,0);
+}
+static int gmatch_aux(lua_State*L){
+MatchState ms;
+size_t ls;
+const char*s=lua_tolstring(L,lua_upvalueindex(1),&ls);
+const char*p=lua_tostring(L,lua_upvalueindex(2));
+const char*src;
+ms.L=L;
+ms.src_init=s;
+ms.src_end=s+ls;
+for(src=s+(size_t)lua_tointeger(L,lua_upvalueindex(3));
+src<=ms.src_end;
+src++){
+const char*e;
+ms.level=0;
+if((e=match(&ms,src,p))!=NULL){
+lua_Integer newstart=e-s;
+if(e==src)newstart++;
+lua_pushinteger(L,newstart);
+lua_replace(L,lua_upvalueindex(3));
+return push_captures(&ms,src,e);
+}
+}
+return 0;
+}
+static int gmatch(lua_State*L){
+luaL_checkstring(L,1);
+luaL_checkstring(L,2);
+lua_settop(L,2);
+lua_pushinteger(L,0);
+lua_pushcclosure(L,gmatch_aux,3);
+return 1;
+}
+static void add_s(MatchState*ms,luaL_Buffer*b,const char*s,
+const char*e){
+size_t l,i;
+const char*news=lua_tolstring(ms->L,3,&l);
+for(i=0;i<l;i++){
+if(news[i]!='%')
+luaL_addchar(b,news[i]);
+else{
+i++;
+if(!isdigit(uchar(news[i])))
+luaL_addchar(b,news[i]);
+else if(news[i]=='0')
+luaL_addlstring(b,s,e-s);
+else{
+push_onecapture(ms,news[i]-'1',s,e);
+luaL_addvalue(b);
+}
+}
+}
+}
+static void add_value(MatchState*ms,luaL_Buffer*b,const char*s,
+const char*e){
+lua_State*L=ms->L;
+switch(lua_type(L,3)){
+case 3:
+case 4:{
+add_s(ms,b,s,e);
+return;
+}
+case 6:{
+int n;
+lua_pushvalue(L,3);
+n=push_captures(ms,s,e);
+lua_call(L,n,1);
+break;
+}
+case 5:{
+push_onecapture(ms,0,s,e);
+lua_gettable(L,3);
+break;
+}
+}
+if(!lua_toboolean(L,-1)){
+lua_pop(L,1);
+lua_pushlstring(L,s,e-s);
+}
+else if(!lua_isstring(L,-1))
+luaL_error(L,"invalid replacement value (a %s)",luaL_typename(L,-1));
+luaL_addvalue(b);
+}
+static int str_gsub(lua_State*L){
+size_t srcl;
+const char*src=luaL_checklstring(L,1,&srcl);
+const char*p=luaL_checkstring(L,2);
+int tr=lua_type(L,3);
+int max_s=luaL_optint(L,4,srcl+1);
+int anchor=(*p=='^')?(p++,1):0;
+int n=0;
+MatchState ms;
+luaL_Buffer b;
+luaL_argcheck(L,tr==3||tr==4||
+tr==6||tr==5,3,
+"string/function/table expected");
+luaL_buffinit(L,&b);
+ms.L=L;
+ms.src_init=src;
+ms.src_end=src+srcl;
+while(n<max_s){
+const char*e;
+ms.level=0;
+e=match(&ms,src,p);
+if(e){
+n++;
+add_value(&ms,&b,src,e);
+}
+if(e&&e>src)
+src=e;
+else if(src<ms.src_end)
+luaL_addchar(&b,*src++);
+else break;
+if(anchor)break;
+}
+luaL_addlstring(&b,src,ms.src_end-src);
+luaL_pushresult(&b);
+lua_pushinteger(L,n);
+return 2;
+}
+static void addquoted(lua_State*L,luaL_Buffer*b,int arg){
+size_t l;
+const char*s=luaL_checklstring(L,arg,&l);
+luaL_addchar(b,'"');
+while(l--){
+switch(*s){
+case'"':case'\\':case'\n':{
+luaL_addchar(b,'\\');
+luaL_addchar(b,*s);
+break;
+}
+case'\r':{
+luaL_addlstring(b,"\\r",2);
+break;
+}
+case'\0':{
+luaL_addlstring(b,"\\000",4);
+break;
+}
+default:{
+luaL_addchar(b,*s);
+break;
+}
+}
+s++;
+}
+luaL_addchar(b,'"');
+}
+static const char*scanformat(lua_State*L,const char*strfrmt,char*form){
+const char*p=strfrmt;
+while(*p!='\0'&&strchr("-+ #0",*p)!=NULL)p++;
+if((size_t)(p-strfrmt)>=sizeof("-+ #0"))
+luaL_error(L,"invalid format (repeated flags)");
+if(isdigit(uchar(*p)))p++;
+if(isdigit(uchar(*p)))p++;
+if(*p=='.'){
+p++;
+if(isdigit(uchar(*p)))p++;
+if(isdigit(uchar(*p)))p++;
+}
+if(isdigit(uchar(*p)))
+luaL_error(L,"invalid format (width or precision too long)");
+*(form++)='%';
+strncpy(form,strfrmt,p-strfrmt+1);
+form+=p-strfrmt+1;
+*form='\0';
+return p;
+}
+static void addintlen(char*form){
+size_t l=strlen(form);
+char spec=form[l-1];
+strcpy(form+l-1,"l");
+form[l+sizeof("l")-2]=spec;
+form[l+sizeof("l")-1]='\0';
+}
+static int str_format(lua_State*L){
+int top=lua_gettop(L);
+int arg=1;
+size_t sfl;
+const char*strfrmt=luaL_checklstring(L,arg,&sfl);
+const char*strfrmt_end=strfrmt+sfl;
+luaL_Buffer b;
+luaL_buffinit(L,&b);
+while(strfrmt<strfrmt_end){
+if(*strfrmt!='%')
+luaL_addchar(&b,*strfrmt++);
+else if(*++strfrmt=='%')
+luaL_addchar(&b,*strfrmt++);
+else{
+char form[(sizeof("-+ #0")+sizeof("l")+10)];
+char buff[512];
+if(++arg>top)
+luaL_argerror(L,arg,"no value");
+strfrmt=scanformat(L,strfrmt,form);
+switch(*strfrmt++){
+case'c':{
+sprintf(buff,form,(int)luaL_checknumber(L,arg));
+break;
+}
+case'd':case'i':{
+addintlen(form);
+sprintf(buff,form,(long)luaL_checknumber(L,arg));
+break;
+}
+case'o':case'u':case'x':case'X':{
+addintlen(form);
+sprintf(buff,form,(unsigned long)luaL_checknumber(L,arg));
+break;
+}
+case'e':case'E':case'f':
+case'g':case'G':{
+sprintf(buff,form,(double)luaL_checknumber(L,arg));
+break;
+}
+case'q':{
+addquoted(L,&b,arg);
+continue;
+}
+case's':{
+size_t l;
+const char*s=luaL_checklstring(L,arg,&l);
+if(!strchr(form,'.')&&l>=100){
+lua_pushvalue(L,arg);
+luaL_addvalue(&b);
+continue;
+}
+else{
+sprintf(buff,form,s);
+break;
+}
+}
+default:{
+return luaL_error(L,"invalid option "LUA_QL("%%%c")" to "
+LUA_QL("format"),*(strfrmt-1));
+}
+}
+luaL_addlstring(&b,buff,strlen(buff));
+}
+}
+luaL_pushresult(&b);
+return 1;
+}
+static const luaL_Reg strlib[]={
+{"byte",str_byte},
+{"char",str_char},
+{"find",str_find},
+{"format",str_format},
+{"gmatch",gmatch},
+{"gsub",str_gsub},
+{"lower",str_lower},
+{"match",str_match},
+{"rep",str_rep},
+{"sub",str_sub},
+{"upper",str_upper},
+{NULL,NULL}
+};
+static void createmetatable(lua_State*L){
+lua_createtable(L,0,1);
+lua_pushliteral(L,"");
+lua_pushvalue(L,-2);
+lua_setmetatable(L,-2);
+lua_pop(L,1);
+lua_pushvalue(L,-2);
+lua_setfield(L,-2,"__index");
+lua_pop(L,1);
+}
+static int luaopen_string(lua_State*L){
+luaL_register(L,"string",strlib);
+createmetatable(L);
+return 1;
+}
+static const luaL_Reg lualibs[]={
+{"",luaopen_base},
+{"table",luaopen_table},
+{"io",luaopen_io},
+{"os",luaopen_os},
+{"string",luaopen_string},
+{NULL,NULL}
+};
+static void luaL_openlibs(lua_State*L){
+const luaL_Reg*lib=lualibs;
+for(;lib->func;lib++){
+lua_pushcfunction(L,lib->func);
+lua_pushstring(L,lib->name);
+lua_call(L,1,0);
+}
+}
+typedef unsigned int UB;
+static UB barg(lua_State*L,int idx){
+union{lua_Number n;U64 b;}bn;
+bn.n=lua_tonumber(L,idx)+6755399441055744.0;
+if(bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
+return(UB)bn.b;
+}
+#define BRET(b)lua_pushnumber(L,(lua_Number)(int)(b));return 1;
+static int tobit(lua_State*L){
+BRET(barg(L,1))}
+static int bnot(lua_State*L){
+BRET(~barg(L,1))}
+static int band(lua_State*L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
+static int bor(lua_State*L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
+static int bxor(lua_State*L){
+int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
+static int lshift(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET(b<<n)}
+static int rshift(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET(b>>n)}
+static int arshift(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
+static int rol(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((b<<n)|(b>>(32-n)))}
+static int ror(lua_State*L){
+UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
+static int bswap(lua_State*L){
+UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
+static int tohex(lua_State*L){
+UB b=barg(L,1);
+int n=lua_isnone(L,2)?8:(int)barg(L,2);
+const char*hexdigits="0123456789abcdef";
+char buf[8];
+int i;
+if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
+if(n>8)n=8;
+for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
+lua_pushlstring(L,buf,(size_t)n);
+return 1;
+}
+static const struct luaL_Reg bitlib[]={
+{"tobit",tobit},
+{"bnot",bnot},
+{"band",band},
+{"bor",bor},
+{"bxor",bxor},
+{"lshift",lshift},
+{"rshift",rshift},
+{"arshift",arshift},
+{"rol",rol},
+{"ror",ror},
+{"bswap",bswap},
+{"tohex",tohex},
+{NULL,NULL}
+};
+int main(int argc,char**argv){
+lua_State*L=luaL_newstate();
+int i;
+luaL_openlibs(L);
+luaL_register(L,"bit",bitlib);
+if(argc<2)return sizeof(void*);
+lua_createtable(L,0,1);
+lua_pushstring(L,argv[1]);
+lua_rawseti(L,-2,0);
+lua_setglobal(L,"arg");
+if(luaL_loadfile(L,argv[1]))
+goto err;
+for(i=2;i<argc;i++)
+lua_pushstring(L,argv[i]);
+if(lua_pcall(L,argc-2,0,0)){
+err:
+fprintf(stderr,"Error: %s\n",lua_tostring(L,-1));
+return 1;
+}
+lua_close(L);
+return 0;
+}
diff --git a/ext/opcache/jit/libudis86/LICENSE b/ext/opcache/jit/libudis86/LICENSE
new file mode 100644
index 0000000000..580f35987f
--- /dev/null
+++ b/ext/opcache/jit/libudis86/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2002-2012, Vivek Thampi <vivek.mt@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/ext/opcache/jit/libudis86/decode.c b/ext/opcache/jit/libudis86/decode.c
new file mode 100644
index 0000000000..1c97d280d9
--- /dev/null
+++ b/ext/opcache/jit/libudis86/decode.c
@@ -0,0 +1,1266 @@
+/* udis86 - libudis86/decode.c
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "udint.h"
+#include "types.h"
+#include "extern.h"
+#include "decode.h"
+
+#ifndef __UD_STANDALONE__
+# include <string.h>
+#endif /* __UD_STANDALONE__ */
+
+/* The max number of prefixes to an instruction */
+#define MAX_PREFIXES 15
+
+/* rex prefix bits */
+#define REX_W(r) ( ( 0xF & ( r ) ) >> 3 )
+#define REX_R(r) ( ( 0x7 & ( r ) ) >> 2 )
+#define REX_X(r) ( ( 0x3 & ( r ) ) >> 1 )
+#define REX_B(r) ( ( 0x1 & ( r ) ) >> 0 )
+#define REX_PFX_MASK(n) ( ( P_REXW(n) << 3 ) | \
+ ( P_REXR(n) << 2 ) | \
+ ( P_REXX(n) << 1 ) | \
+ ( P_REXB(n) << 0 ) )
+
+/* scable-index-base bits */
+#define SIB_S(b) ( ( b ) >> 6 )
+#define SIB_I(b) ( ( ( b ) >> 3 ) & 7 )
+#define SIB_B(b) ( ( b ) & 7 )
+
+/* modrm bits */
+#define MODRM_REG(b) ( ( ( b ) >> 3 ) & 7 )
+#define MODRM_NNN(b) ( ( ( b ) >> 3 ) & 7 )
+#define MODRM_MOD(b) ( ( ( b ) >> 6 ) & 3 )
+#define MODRM_RM(b) ( ( b ) & 7 )
+
+static int decode_ext(struct ud *u, uint16_t ptr);
+static int decode_opcode(struct ud *u);
+
+enum reg_class { /* register classes */
+ REGCLASS_GPR,
+ REGCLASS_MMX,
+ REGCLASS_CR,
+ REGCLASS_DB,
+ REGCLASS_SEG,
+ REGCLASS_XMM
+};
+
+ /*
+ * inp_start
+ * Should be called before each de-code operation.
+ */
+static void
+inp_start(struct ud *u)
+{
+ u->inp_ctr = 0;
+}
+
+static uint8_t
+inp_peek(struct ud *u)
+{
+ if (u->inp_end == 0) {
+ if (u->inp_buf != NULL) {
+ if (u->inp_buf_index < u->inp_buf_size) {
+ return u->inp_buf[u->inp_buf_index];
+ }
+ } else if (u->inp_peek != UD_EOI) {
+ return u->inp_peek;
+ } else {
+ int c;
+ if ((c = u->inp_hook(u)) != UD_EOI) {
+ u->inp_peek = c;
+ return u->inp_peek;
+ }
+ }
+ }
+ u->inp_end = 1;
+ UDERR(u, "byte expected, eoi received\n");
+ return 0;
+}
+
+static uint8_t
+inp_next(struct ud *u)
+{
+ if (u->inp_end == 0) {
+ if (u->inp_buf != NULL) {
+ if (u->inp_buf_index < u->inp_buf_size) {
+ u->inp_ctr++;
+ return (u->inp_curr = u->inp_buf[u->inp_buf_index++]);
+ }
+ } else {
+ int c = u->inp_peek;
+ if (c != UD_EOI || (c = u->inp_hook(u)) != UD_EOI) {
+ u->inp_peek = UD_EOI;
+ u->inp_curr = c;
+ u->inp_sess[u->inp_ctr++] = u->inp_curr;
+ return u->inp_curr;
+ }
+ }
+ }
+ u->inp_end = 1;
+ UDERR(u, "byte expected, eoi received\n");
+ return 0;
+}
+
+static uint8_t
+inp_curr(struct ud *u)
+{
+ return u->inp_curr;
+}
+
+
+/*
+ * inp_uint8
+ * int_uint16
+ * int_uint32
+ * int_uint64
+ * Load little-endian values from input
+ */
+static uint8_t
+inp_uint8(struct ud* u)
+{
+ return inp_next(u);
+}
+
+static uint16_t
+inp_uint16(struct ud* u)
+{
+ uint16_t r, ret;
+
+ ret = inp_next(u);
+ r = inp_next(u);
+ return ret | (r << 8);
+}
+
+static uint32_t
+inp_uint32(struct ud* u)
+{
+ uint32_t r, ret;
+
+ ret = inp_next(u);
+ r = inp_next(u);
+ ret = ret | (r << 8);
+ r = inp_next(u);
+ ret = ret | (r << 16);
+ r = inp_next(u);
+ return ret | (r << 24);
+}
+
+static uint64_t
+inp_uint64(struct ud* u)
+{
+ uint64_t r, ret;
+
+ ret = inp_next(u);
+ r = inp_next(u);
+ ret = ret | (r << 8);
+ r = inp_next(u);
+ ret = ret | (r << 16);
+ r = inp_next(u);
+ ret = ret | (r << 24);
+ r = inp_next(u);
+ ret = ret | (r << 32);
+ r = inp_next(u);
+ ret = ret | (r << 40);
+ r = inp_next(u);
+ ret = ret | (r << 48);
+ r = inp_next(u);
+ return ret | (r << 56);
+}
+
+
+static UD_INLINE int
+eff_opr_mode(int dis_mode, int rex_w, int pfx_opr)
+{
+ if (dis_mode == 64) {
+ return rex_w ? 64 : (pfx_opr ? 16 : 32);
+ } else if (dis_mode == 32) {
+ return pfx_opr ? 16 : 32;
+ } else {
+ UD_ASSERT(dis_mode == 16);
+ return pfx_opr ? 32 : 16;
+ }
+}
+
+
+static UD_INLINE int
+eff_adr_mode(int dis_mode, int pfx_adr)
+{
+ if (dis_mode == 64) {
+ return pfx_adr ? 32 : 64;
+ } else if (dis_mode == 32) {
+ return pfx_adr ? 16 : 32;
+ } else {
+ UD_ASSERT(dis_mode == 16);
+ return pfx_adr ? 32 : 16;
+ }
+}
+
+
+/*
+ * decode_prefixes
+ *
+ * Extracts instruction prefixes.
+ */
+static int
+decode_prefixes(struct ud *u)
+{
+ int done = 0;
+ uint8_t curr = 0, last = 0;
+ UD_RETURN_ON_ERROR(u);
+
+ do {
+ last = curr;
+ curr = inp_next(u);
+ UD_RETURN_ON_ERROR(u);
+ if (u->inp_ctr == MAX_INSN_LENGTH) {
+ UD_RETURN_WITH_ERROR(u, "max instruction length");
+ }
+
+ switch (curr)
+ {
+ case 0x2E:
+ u->pfx_seg = UD_R_CS;
+ break;
+ case 0x36:
+ u->pfx_seg = UD_R_SS;
+ break;
+ case 0x3E:
+ u->pfx_seg = UD_R_DS;
+ break;
+ case 0x26:
+ u->pfx_seg = UD_R_ES;
+ break;
+ case 0x64:
+ u->pfx_seg = UD_R_FS;
+ break;
+ case 0x65:
+ u->pfx_seg = UD_R_GS;
+ break;
+ case 0x67: /* adress-size override prefix */
+ u->pfx_adr = 0x67;
+ break;
+ case 0xF0:
+ u->pfx_lock = 0xF0;
+ break;
+ case 0x66:
+ u->pfx_opr = 0x66;
+ break;
+ case 0xF2:
+ u->pfx_str = 0xf2;
+ break;
+ case 0xF3:
+ u->pfx_str = 0xf3;
+ break;
+ default:
+ /* consume if rex */
+ done = (u->dis_mode == 64 && (curr & 0xF0) == 0x40) ? 0 : 1;
+ break;
+ }
+ } while (!done);
+ /* rex prefixes in 64bit mode, must be the last prefix */
+ if (u->dis_mode == 64 && (last & 0xF0) == 0x40) {
+ u->pfx_rex = last;
+ }
+ return 0;
+}
+
+
+/*
+ * vex_l, vex_w
+ * Return the vex.L and vex.W bits
+ */
+static UD_INLINE uint8_t
+vex_l(const struct ud *u)
+{
+ UD_ASSERT(u->vex_op != 0);
+ return ((u->vex_op == 0xc4 ? u->vex_b2 : u->vex_b1) >> 2) & 1;
+}
+
+static UD_INLINE uint8_t
+vex_w(const struct ud *u)
+{
+ UD_ASSERT(u->vex_op != 0);
+ return u->vex_op == 0xc4 ? ((u->vex_b2 >> 7) & 1) : 0;
+}
+
+
+static UD_INLINE uint8_t
+modrm(struct ud * u)
+{
+ if ( !u->have_modrm ) {
+ u->modrm = inp_next( u );
+ u->modrm_offset = (uint8_t) (u->inp_ctr - 1);
+ u->have_modrm = 1;
+ }
+ return u->modrm;
+}
+
+
+static unsigned int
+resolve_operand_size(const struct ud* u, ud_operand_size_t osize)
+{
+ switch (osize) {
+ case SZ_V:
+ return u->opr_mode;
+ case SZ_Z:
+ return u->opr_mode == 16 ? 16 : 32;
+ case SZ_Y:
+ return u->opr_mode == 16 ? 32 : u->opr_mode;
+ case SZ_RDQ:
+ return u->dis_mode == 64 ? 64 : 32;
+ case SZ_X:
+ UD_ASSERT(u->vex_op != 0);
+ return (P_VEXL(u->itab_entry->prefix) && vex_l(u)) ? SZ_QQ : SZ_DQ;
+ default:
+ return osize;
+ }
+}
+
+
+static int resolve_mnemonic( struct ud* u )
+{
+ /* resolve 3dnow weirdness. */
+ if ( u->mnemonic == UD_I3dnow ) {
+ u->mnemonic = ud_itab[ u->le->table[ inp_curr( u ) ] ].mnemonic;
+ }
+ /* SWAPGS is only valid in 64bits mode */
+ if ( u->mnemonic == UD_Iswapgs && u->dis_mode != 64 ) {
+ UDERR(u, "swapgs invalid in 64bits mode\n");
+ return -1;
+ }
+
+ if (u->mnemonic == UD_Ixchg) {
+ if ((u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_AX &&
+ u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_AX) ||
+ (u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_EAX &&
+ u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_EAX)) {
+ u->operand[0].type = UD_NONE;
+ u->operand[1].type = UD_NONE;
+ u->mnemonic = UD_Inop;
+ }
+ }
+
+ if (u->mnemonic == UD_Inop && u->pfx_repe) {
+ u->pfx_repe = 0;
+ u->mnemonic = UD_Ipause;
+ }
+ return 0;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * decode_a()- Decodes operands of the type seg:offset
+ * -----------------------------------------------------------------------------
+ */
+static void
+decode_a(struct ud* u, struct ud_operand *op)
+{
+ if (u->opr_mode == 16) {
+ /* seg16:off16 */
+ op->type = UD_OP_PTR;
+ op->size = 32;
+ op->lval.ptr.off = inp_uint16(u);
+ op->lval.ptr.seg = inp_uint16(u);
+ } else {
+ /* seg16:off32 */
+ op->type = UD_OP_PTR;
+ op->size = 48;
+ op->lval.ptr.off = inp_uint32(u);
+ op->lval.ptr.seg = inp_uint16(u);
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * decode_gpr() - Returns decoded General Purpose Register
+ * -----------------------------------------------------------------------------
+ */
+static enum ud_type
+decode_gpr(register struct ud* u, unsigned int s, unsigned char rm)
+{
+ switch (s) {
+ case 64:
+ return UD_R_RAX + rm;
+ case 32:
+ return UD_R_EAX + rm;
+ case 16:
+ return UD_R_AX + rm;
+ case 8:
+ if (u->dis_mode == 64 && u->pfx_rex) {
+ if (rm >= 4)
+ return UD_R_SPL + (rm-4);
+ return UD_R_AL + rm;
+ } else return UD_R_AL + rm;
+ case 0:
+ /* invalid size in case of a decode error */
+ UD_ASSERT(u->error);
+ return UD_NONE;
+ default:
+ UD_ASSERT(!"invalid operand size");
+ return UD_NONE;
+ }
+}
+
+static void
+decode_reg(struct ud *u,
+ struct ud_operand *opr,
+ int type,
+ int num,
+ int size)
+{
+ int reg;
+ size = resolve_operand_size(u, size);
+ switch (type) {
+ case REGCLASS_GPR : reg = decode_gpr(u, size, num); break;
+ case REGCLASS_MMX : reg = UD_R_MM0 + (num & 7); break;
+ case REGCLASS_XMM :
+ reg = num + (size == SZ_QQ ? UD_R_YMM0 : UD_R_XMM0);
+ break;
+ case REGCLASS_CR : reg = UD_R_CR0 + num; break;
+ case REGCLASS_DB : reg = UD_R_DR0 + num; break;
+ case REGCLASS_SEG : {
+ /*
+ * Only 6 segment registers, anything else is an error.
+ */
+ if ((num & 7) > 5) {
+ UDERR(u, "invalid segment register value\n");
+ return;
+ } else {
+ reg = UD_R_ES + (num & 7);
+ }
+ break;
+ }
+ default:
+ UD_ASSERT(!"invalid register type");
+ return;
+ }
+ opr->type = UD_OP_REG;
+ opr->base = reg;
+ opr->size = size;
+}
+
+
+/*
+ * decode_imm
+ *
+ * Decode Immediate values.
+ */
+static void
+decode_imm(struct ud* u, unsigned int size, struct ud_operand *op)
+{
+ op->size = resolve_operand_size(u, size);
+ op->type = UD_OP_IMM;
+
+ switch (op->size) {
+ case 8: op->lval.sbyte = inp_uint8(u); break;
+ case 16: op->lval.uword = inp_uint16(u); break;
+ case 32: op->lval.udword = inp_uint32(u); break;
+ case 64: op->lval.uqword = inp_uint64(u); break;
+ default: return;
+ }
+}
+
+
+/*
+ * decode_mem_disp
+ *
+ * Decode mem address displacement.
+ */
+static void
+decode_mem_disp(struct ud* u, unsigned int size, struct ud_operand *op)
+{
+ switch (size) {
+ case 8:
+ op->offset = 8;
+ op->lval.ubyte = inp_uint8(u);
+ break;
+ case 16:
+ op->offset = 16;
+ op->lval.uword = inp_uint16(u);
+ break;
+ case 32:
+ op->offset = 32;
+ op->lval.udword = inp_uint32(u);
+ break;
+ case 64:
+ op->offset = 64;
+ op->lval.uqword = inp_uint64(u);
+ break;
+ default:
+ return;
+ }
+}
+
+
+/*
+ * decode_modrm_reg
+ *
+ * Decodes reg field of mod/rm byte
+ *
+ */
+static UD_INLINE void
+decode_modrm_reg(struct ud *u,
+ struct ud_operand *operand,
+ unsigned int type,
+ unsigned int size)
+{
+ uint8_t reg = (REX_R(u->_rex) << 3) | MODRM_REG(modrm(u));
+ decode_reg(u, operand, type, reg, size);
+}
+
+
+/*
+ * decode_modrm_rm
+ *
+ * Decodes rm field of mod/rm byte
+ *
+ */
+static void
+decode_modrm_rm(struct ud *u,
+ struct ud_operand *op,
+ unsigned char type, /* register type */
+ unsigned int size) /* operand size */
+
+{
+ size_t offset = 0;
+ unsigned char mod, rm;
+
+ /* get mod, r/m and reg fields */
+ mod = MODRM_MOD(modrm(u));
+ rm = (REX_B(u->_rex) << 3) | MODRM_RM(modrm(u));
+
+ /*
+ * If mod is 11b, then the modrm.rm specifies a register.
+ *
+ */
+ if (mod == 3) {
+ decode_reg(u, op, type, rm, size);
+ return;
+ }
+
+ /*
+ * !11b => Memory Address
+ */
+ op->type = UD_OP_MEM;
+ op->size = resolve_operand_size(u, size);
+
+ if (u->adr_mode == 64) {
+ op->base = UD_R_RAX + rm;
+ if (mod == 1) {
+ offset = 8;
+ } else if (mod == 2) {
+ offset = 32;
+ } else if (mod == 0 && (rm & 7) == 5) {
+ op->base = UD_R_RIP;
+ offset = 32;
+ } else {
+ offset = 0;
+ }
+ /*
+ * Scale-Index-Base (SIB)
+ */
+ if ((rm & 7) == 4) {
+ inp_next(u);
+
+ op->base = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->_rex) << 3));
+ op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->_rex) << 3));
+ /* special conditions for base reference */
+ if (op->index == UD_R_RSP) {
+ op->index = UD_NONE;
+ op->scale = UD_NONE;
+ } else {
+ op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
+ }
+
+ if (op->base == UD_R_RBP || op->base == UD_R_R13) {
+ if (mod == 0) {
+ op->base = UD_NONE;
+ }
+ if (mod == 1) {
+ offset = 8;
+ } else {
+ offset = 32;
+ }
+ }
+ } else {
+ op->scale = UD_NONE;
+ op->index = UD_NONE;
+ }
+ } else if (u->adr_mode == 32) {
+ op->base = UD_R_EAX + rm;
+ if (mod == 1) {
+ offset = 8;
+ } else if (mod == 2) {
+ offset = 32;
+ } else if (mod == 0 && rm == 5) {
+ op->base = UD_NONE;
+ offset = 32;
+ } else {
+ offset = 0;
+ }
+
+ /* Scale-Index-Base (SIB) */
+ if ((rm & 7) == 4) {
+ inp_next(u);
+
+ op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
+ op->index = UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
+ op->base = UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));
+
+ if (op->index == UD_R_ESP) {
+ op->index = UD_NONE;
+ op->scale = UD_NONE;
+ }
+
+ /* special condition for base reference */
+ if (op->base == UD_R_EBP) {
+ if (mod == 0) {
+ op->base = UD_NONE;
+ }
+ if (mod == 1) {
+ offset = 8;
+ } else {
+ offset = 32;
+ }
+ }
+ } else {
+ op->scale = UD_NONE;
+ op->index = UD_NONE;
+ }
+ } else {
+ const unsigned int bases[] = { UD_R_BX, UD_R_BX, UD_R_BP, UD_R_BP,
+ UD_R_SI, UD_R_DI, UD_R_BP, UD_R_BX };
+ const unsigned int indices[] = { UD_R_SI, UD_R_DI, UD_R_SI, UD_R_DI,
+ UD_NONE, UD_NONE, UD_NONE, UD_NONE };
+ op->base = bases[rm & 7];
+ op->index = indices[rm & 7];
+ op->scale = UD_NONE;
+ if (mod == 0 && rm == 6) {
+ offset = 16;
+ op->base = UD_NONE;
+ } else if (mod == 1) {
+ offset = 8;
+ } else if (mod == 2) {
+ offset = 16;
+ }
+ }
+
+ if (offset) {
+ decode_mem_disp(u, offset, op);
+ } else {
+ op->offset = 0;
+ }
+}
+
+
+/*
+ * decode_moffset
+ * Decode offset-only memory operand
+ */
+static void
+decode_moffset(struct ud *u, unsigned int size, struct ud_operand *opr)
+{
+ opr->type = UD_OP_MEM;
+ opr->base = UD_NONE;
+ opr->index = UD_NONE;
+ opr->scale = UD_NONE;
+ opr->size = resolve_operand_size(u, size);
+ decode_mem_disp(u, u->adr_mode, opr);
+}
+
+
+static void
+decode_vex_vvvv(struct ud *u, struct ud_operand *opr, unsigned size)
+{
+ uint8_t vvvv;
+ UD_ASSERT(u->vex_op != 0);
+ vvvv = ((u->vex_op == 0xc4 ? u->vex_b2 : u->vex_b1) >> 3) & 0xf;
+ decode_reg(u, opr, REGCLASS_XMM, (0xf & ~vvvv), size);
+}
+
+
+/*
+ * decode_vex_immreg
+ * Decode source operand encoded in immediate byte [7:4]
+ */
+static int
+decode_vex_immreg(struct ud *u, struct ud_operand *opr, unsigned size)
+{
+ uint8_t imm = inp_next(u);
+ uint8_t mask = u->dis_mode == 64 ? 0xf : 0x7;
+ UD_RETURN_ON_ERROR(u);
+ UD_ASSERT(u->vex_op != 0);
+ decode_reg(u, opr, REGCLASS_XMM, mask & (imm >> 4), size);
+ return 0;
+}
+
+
+/*
+ * decode_operand
+ *
+ * Decodes a single operand.
+ * Returns the type of the operand (UD_NONE if none)
+ */
+static int
+decode_operand(struct ud *u,
+ struct ud_operand *operand,
+ enum ud_operand_code type,
+ unsigned int size)
+{
+ operand->type = UD_NONE;
+ operand->_oprcode = type;
+
+ switch (type) {
+ case OP_A :
+ decode_a(u, operand);
+ break;
+ case OP_MR:
+ decode_modrm_rm(u, operand, REGCLASS_GPR,
+ MODRM_MOD(modrm(u)) == 3 ?
+ Mx_reg_size(size) : Mx_mem_size(size));
+ break;
+ case OP_F:
+ u->br_far = 1;
+ /* intended fall through */
+ case OP_M:
+ if (MODRM_MOD(modrm(u)) == 3) {
+ UDERR(u, "expected modrm.mod != 3\n");
+ }
+ /* intended fall through */
+ case OP_E:
+ decode_modrm_rm(u, operand, REGCLASS_GPR, size);
+ break;
+ case OP_G:
+ decode_modrm_reg(u, operand, REGCLASS_GPR, size);
+ break;
+ case OP_sI:
+ case OP_I:
+ decode_imm(u, size, operand);
+ break;
+ case OP_I1:
+ operand->type = UD_OP_CONST;
+ operand->lval.udword = 1;
+ break;
+ case OP_N:
+ if (MODRM_MOD(modrm(u)) != 3) {
+ UDERR(u, "expected modrm.mod == 3\n");
+ }
+ /* intended fall through */
+ case OP_Q:
+ decode_modrm_rm(u, operand, REGCLASS_MMX, size);
+ break;
+ case OP_P:
+ decode_modrm_reg(u, operand, REGCLASS_MMX, size);
+ break;
+ case OP_U:
+ if (MODRM_MOD(modrm(u)) != 3) {
+ UDERR(u, "expected modrm.mod == 3\n");
+ }
+ /* intended fall through */
+ case OP_W:
+ decode_modrm_rm(u, operand, REGCLASS_XMM, size);
+ break;
+ case OP_V:
+ decode_modrm_reg(u, operand, REGCLASS_XMM, size);
+ break;
+ case OP_H:
+ decode_vex_vvvv(u, operand, size);
+ break;
+ case OP_MU:
+ decode_modrm_rm(u, operand, REGCLASS_XMM,
+ MODRM_MOD(modrm(u)) == 3 ?
+ Mx_reg_size(size) : Mx_mem_size(size));
+ break;
+ case OP_S:
+ decode_modrm_reg(u, operand, REGCLASS_SEG, size);
+ break;
+ case OP_O:
+ decode_moffset(u, size, operand);
+ break;
+ case OP_R0:
+ case OP_R1:
+ case OP_R2:
+ case OP_R3:
+ case OP_R4:
+ case OP_R5:
+ case OP_R6:
+ case OP_R7:
+ decode_reg(u, operand, REGCLASS_GPR,
+ (REX_B(u->_rex) << 3) | (type - OP_R0), size);
+ break;
+ case OP_AL:
+ case OP_AX:
+ case OP_eAX:
+ case OP_rAX:
+ decode_reg(u, operand, REGCLASS_GPR, 0, size);
+ break;
+ case OP_CL:
+ case OP_CX:
+ case OP_eCX:
+ decode_reg(u, operand, REGCLASS_GPR, 1, size);
+ break;
+ case OP_DL:
+ case OP_DX:
+ case OP_eDX:
+ decode_reg(u, operand, REGCLASS_GPR, 2, size);
+ break;
+ case OP_ES:
+ case OP_CS:
+ case OP_DS:
+ case OP_SS:
+ case OP_FS:
+ case OP_GS:
+ /* in 64bits mode, only fs and gs are allowed */
+ if (u->dis_mode == 64) {
+ if (type != OP_FS && type != OP_GS) {
+ UDERR(u, "invalid segment register in 64bits\n");
+ }
+ }
+ operand->type = UD_OP_REG;
+ operand->base = (type - OP_ES) + UD_R_ES;
+ operand->size = 16;
+ break;
+ case OP_J :
+ decode_imm(u, size, operand);
+ operand->type = UD_OP_JIMM;
+ break ;
+ case OP_R :
+ if (MODRM_MOD(modrm(u)) != 3) {
+ UDERR(u, "expected modrm.mod == 3\n");
+ }
+ decode_modrm_rm(u, operand, REGCLASS_GPR, size);
+ break;
+ case OP_C:
+ decode_modrm_reg(u, operand, REGCLASS_CR, size);
+ break;
+ case OP_D:
+ decode_modrm_reg(u, operand, REGCLASS_DB, size);
+ break;
+ case OP_I3 :
+ operand->type = UD_OP_CONST;
+ operand->lval.sbyte = 3;
+ break;
+ case OP_ST0:
+ case OP_ST1:
+ case OP_ST2:
+ case OP_ST3:
+ case OP_ST4:
+ case OP_ST5:
+ case OP_ST6:
+ case OP_ST7:
+ operand->type = UD_OP_REG;
+ operand->base = (type - OP_ST0) + UD_R_ST0;
+ operand->size = 80;
+ break;
+ case OP_L:
+ decode_vex_immreg(u, operand, size);
+ break;
+ default :
+ operand->type = UD_NONE;
+ break;
+ }
+ return operand->type;
+}
+
+
+/*
+ * decode_operands
+ *
+ * Disassemble up to 3 operands of the current instruction being
+ * disassembled. By the end of the function, the operand fields
+ * of the ud structure will have been filled.
+ */
+static int
+decode_operands(struct ud* u)
+{
+ decode_operand(u, &u->operand[0],
+ u->itab_entry->operand1.type,
+ u->itab_entry->operand1.size);
+ if (u->operand[0].type != UD_NONE) {
+ decode_operand(u, &u->operand[1],
+ u->itab_entry->operand2.type,
+ u->itab_entry->operand2.size);
+ }
+ if (u->operand[1].type != UD_NONE) {
+ decode_operand(u, &u->operand[2],
+ u->itab_entry->operand3.type,
+ u->itab_entry->operand3.size);
+ }
+ if (u->operand[2].type != UD_NONE) {
+ decode_operand(u, &u->operand[3],
+ u->itab_entry->operand4.type,
+ u->itab_entry->operand4.size);
+ }
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * clear_insn() - clear instruction structure
+ * -----------------------------------------------------------------------------
+ */
+static void
+clear_insn(register struct ud* u)
+{
+ u->error = 0;
+ u->pfx_seg = 0;
+ u->pfx_opr = 0;
+ u->pfx_adr = 0;
+ u->pfx_lock = 0;
+ u->pfx_repne = 0;
+ u->pfx_rep = 0;
+ u->pfx_repe = 0;
+ u->pfx_rex = 0;
+ u->pfx_str = 0;
+ u->mnemonic = UD_Inone;
+ u->itab_entry = NULL;
+ u->have_modrm = 0;
+ u->br_far = 0;
+ u->vex_op = 0;
+ u->_rex = 0;
+ u->operand[0].type = UD_NONE;
+ u->operand[1].type = UD_NONE;
+ u->operand[2].type = UD_NONE;
+ u->operand[3].type = UD_NONE;
+}
+
+
+static UD_INLINE int
+resolve_pfx_str(struct ud* u)
+{
+ if (u->pfx_str == 0xf3) {
+ if (P_STR(u->itab_entry->prefix)) {
+ u->pfx_rep = 0xf3;
+ } else {
+ u->pfx_repe = 0xf3;
+ }
+ } else if (u->pfx_str == 0xf2) {
+ u->pfx_repne = 0xf3;
+ }
+ return 0;
+}
+
+
+static int
+resolve_mode( struct ud* u )
+{
+ int default64;
+ /* if in error state, bail out */
+ if ( u->error ) return -1;
+
+ /* propagate prefix effects */
+ if ( u->dis_mode == 64 ) { /* set 64bit-mode flags */
+
+ /* Check validity of instruction m64 */
+ if ( P_INV64( u->itab_entry->prefix ) ) {
+ UDERR(u, "instruction invalid in 64bits\n");
+ return -1;
+ }
+
+ /* compute effective rex based on,
+ * - vex prefix (if any)
+ * - rex prefix (if any, and not vex)
+ * - allowed prefixes specified by the opcode map
+ */
+ if (u->vex_op == 0xc4) {
+ /* vex has rex.rxb in 1's complement */
+ u->_rex = ((~(u->vex_b1 >> 5) & 0x7) /* rex.0rxb */ |
+ ((u->vex_b2 >> 4) & 0x8) /* rex.w000 */);
+ } else if (u->vex_op == 0xc5) {
+ /* vex has rex.r in 1's complement */
+ u->_rex = (~(u->vex_b1 >> 5)) & 4;
+ } else {
+ UD_ASSERT(u->vex_op == 0);
+ u->_rex = u->pfx_rex;
+ }
+ u->_rex &= REX_PFX_MASK(u->itab_entry->prefix);
+
+ /* whether this instruction has a default operand size of
+ * 64bit, also hardcoded into the opcode map.
+ */
+ default64 = P_DEF64( u->itab_entry->prefix );
+ /* calculate effective operand size */
+ if (REX_W(u->_rex)) {
+ u->opr_mode = 64;
+ } else if ( u->pfx_opr ) {
+ u->opr_mode = 16;
+ } else {
+ /* unless the default opr size of instruction is 64,
+ * the effective operand size in the absence of rex.w
+ * prefix is 32.
+ */
+ u->opr_mode = default64 ? 64 : 32;
+ }
+
+ /* calculate effective address size */
+ u->adr_mode = (u->pfx_adr) ? 32 : 64;
+ } else if ( u->dis_mode == 32 ) { /* set 32bit-mode flags */
+ u->opr_mode = ( u->pfx_opr ) ? 16 : 32;
+ u->adr_mode = ( u->pfx_adr ) ? 16 : 32;
+ } else if ( u->dis_mode == 16 ) { /* set 16bit-mode flags */
+ u->opr_mode = ( u->pfx_opr ) ? 32 : 16;
+ u->adr_mode = ( u->pfx_adr ) ? 32 : 16;
+ }
+
+ return 0;
+}
+
+
+static UD_INLINE int
+decode_insn(struct ud *u, uint16_t ptr)
+{
+ UD_ASSERT((ptr & 0x8000) == 0);
+ u->itab_entry = &ud_itab[ ptr ];
+ u->mnemonic = u->itab_entry->mnemonic;
+ return (resolve_pfx_str(u) == 0 &&
+ resolve_mode(u) == 0 &&
+ decode_operands(u) == 0 &&
+ resolve_mnemonic(u) == 0) ? 0 : -1;
+}
+
+
+/*
+ * decode_3dnow()
+ *
+ * Decoding 3dnow is a little tricky because of its strange opcode
+ * structure. The final opcode disambiguation depends on the last
+ * byte that comes after the operands have been decoded. Fortunately,
+ * all 3dnow instructions have the same set of operand types. So we
+ * go ahead and decode the instruction by picking an arbitrarily chosen
+ * valid entry in the table, decode the operands, and read the final
+ * byte to resolve the menmonic.
+ */
+static UD_INLINE int
+decode_3dnow(struct ud* u)
+{
+ uint16_t ptr;
+ UD_ASSERT(u->le->type == UD_TAB__OPC_3DNOW);
+ UD_ASSERT(u->le->table[0xc] != 0);
+ decode_insn(u, u->le->table[0xc]);
+ inp_next(u);
+ if (u->error) {
+ return -1;
+ }
+ ptr = u->le->table[inp_curr(u)];
+ UD_ASSERT((ptr & 0x8000) == 0);
+ u->mnemonic = ud_itab[ptr].mnemonic;
+ return 0;
+}
+
+
+static int
+decode_ssepfx(struct ud *u)
+{
+ uint8_t idx;
+ uint8_t pfx;
+
+ /*
+ * String prefixes (f2, f3) take precedence over operand
+ * size prefix (66).
+ */
+ pfx = u->pfx_str;
+ if (pfx == 0) {
+ pfx = u->pfx_opr;
+ }
+ idx = ((pfx & 0xf) + 1) / 2;
+ if (u->le->table[idx] == 0) {
+ idx = 0;
+ }
+ if (idx && u->le->table[idx] != 0) {
+ /*
+ * "Consume" the prefix as a part of the opcode, so it is no
+ * longer exported as an instruction prefix.
+ */
+ u->pfx_str = 0;
+ if (pfx == 0x66) {
+ /*
+ * consume "66" only if it was used for decoding, leaving
+ * it to be used as an operands size override for some
+ * simd instructions.
+ */
+ u->pfx_opr = 0;
+ }
+ }
+ return decode_ext(u, u->le->table[idx]);
+}
+
+
+static int
+decode_vex(struct ud *u)
+{
+ uint8_t index;
+ if (u->dis_mode != 64 && MODRM_MOD(inp_peek(u)) != 0x3) {
+ index = 0;
+ } else {
+ u->vex_op = inp_curr(u);
+ u->vex_b1 = inp_next(u);
+ if (u->vex_op == 0xc4) {
+ uint8_t pp, m;
+ /* 3-byte vex */
+ u->vex_b2 = inp_next(u);
+ UD_RETURN_ON_ERROR(u);
+ m = u->vex_b1 & 0x1f;
+ if (m == 0 || m > 3) {
+ UD_RETURN_WITH_ERROR(u, "reserved vex.m-mmmm value");
+ }
+ pp = u->vex_b2 & 0x3;
+ index = (pp << 2) | m;
+ } else {
+ /* 2-byte vex */
+ UD_ASSERT(u->vex_op == 0xc5);
+ index = 0x1 | ((u->vex_b1 & 0x3) << 2);
+ }
+ }
+ return decode_ext(u, u->le->table[index]);
+}
+
+
+/*
+ * decode_ext()
+ *
+ * Decode opcode extensions (if any)
+ */
+static int
+decode_ext(struct ud *u, uint16_t ptr)
+{
+ uint8_t idx = 0;
+ if ((ptr & 0x8000) == 0) {
+ return decode_insn(u, ptr);
+ }
+ u->le = &ud_lookup_table_list[(~0x8000 & ptr)];
+ if (u->le->type == UD_TAB__OPC_3DNOW) {
+ return decode_3dnow(u);
+ }
+
+ switch (u->le->type) {
+ case UD_TAB__OPC_MOD:
+ /* !11 = 0, 11 = 1 */
+ idx = (MODRM_MOD(modrm(u)) + 1) / 4;
+ break;
+ /* disassembly mode/operand size/address size based tables.
+ * 16 = 0,, 32 = 1, 64 = 2
+ */
+ case UD_TAB__OPC_MODE:
+ idx = u->dis_mode != 64 ? 0 : 1;
+ break;
+ case UD_TAB__OPC_OSIZE:
+ idx = eff_opr_mode(u->dis_mode, REX_W(u->pfx_rex), u->pfx_opr) / 32;
+ break;
+ case UD_TAB__OPC_ASIZE:
+ idx = eff_adr_mode(u->dis_mode, u->pfx_adr) / 32;
+ break;
+ case UD_TAB__OPC_X87:
+ idx = modrm(u) - 0xC0;
+ break;
+ case UD_TAB__OPC_VENDOR:
+ if (u->vendor == UD_VENDOR_ANY) {
+ /* choose a valid entry */
+ idx = (u->le->table[idx] != 0) ? 0 : 1;
+ } else if (u->vendor == UD_VENDOR_AMD) {
+ idx = 0;
+ } else {
+ idx = 1;
+ }
+ break;
+ case UD_TAB__OPC_RM:
+ idx = MODRM_RM(modrm(u));
+ break;
+ case UD_TAB__OPC_REG:
+ idx = MODRM_REG(modrm(u));
+ break;
+ case UD_TAB__OPC_SSE:
+ return decode_ssepfx(u);
+ case UD_TAB__OPC_VEX:
+ return decode_vex(u);
+ case UD_TAB__OPC_VEX_W:
+ idx = vex_w(u);
+ break;
+ case UD_TAB__OPC_VEX_L:
+ idx = vex_l(u);
+ break;
+ case UD_TAB__OPC_TABLE:
+ inp_next(u);
+ return decode_opcode(u);
+ default:
+ UD_ASSERT(!"not reached");
+ break;
+ }
+
+ return decode_ext(u, u->le->table[idx]);
+}
+
+
+static int
+decode_opcode(struct ud *u)
+{
+ uint16_t ptr;
+ UD_ASSERT(u->le->type == UD_TAB__OPC_TABLE);
+ UD_RETURN_ON_ERROR(u);
+ ptr = u->le->table[inp_curr(u)];
+ return decode_ext(u, ptr);
+}
+
+
+/* =============================================================================
+ * ud_decode() - Instruction decoder. Returns the number of bytes decoded.
+ * =============================================================================
+ */
+unsigned int
+ud_decode(struct ud *u)
+{
+ inp_start(u);
+ clear_insn(u);
+ u->le = &ud_lookup_table_list[0];
+ u->error = decode_prefixes(u) == -1 ||
+ decode_opcode(u) == -1 ||
+ u->error;
+ /* Handle decode error. */
+ if (u->error) {
+ /* clear out the decode data. */
+ clear_insn(u);
+ /* mark the sequence of bytes as invalid. */
+ u->itab_entry = &ud_itab[0]; /* entry 0 is invalid */
+ u->mnemonic = u->itab_entry->mnemonic;
+ }
+
+ /* maybe this stray segment override byte
+ * should be spewed out?
+ */
+ if ( !P_SEG( u->itab_entry->prefix ) &&
+ u->operand[0].type != UD_OP_MEM &&
+ u->operand[1].type != UD_OP_MEM )
+ u->pfx_seg = 0;
+
+ u->insn_offset = u->pc; /* set offset of instruction */
+ u->asm_buf_fill = 0; /* set translation buffer index to 0 */
+ u->pc += u->inp_ctr; /* move program counter by bytes decoded */
+
+ /* return number of bytes disassembled. */
+ return u->inp_ctr;
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/ext/opcache/jit/libudis86/decode.h b/ext/opcache/jit/libudis86/decode.h
new file mode 100644
index 0000000000..3949c4e269
--- /dev/null
+++ b/ext/opcache/jit/libudis86/decode.h
@@ -0,0 +1,197 @@
+/* udis86 - libudis86/decode.h
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_DECODE_H
+#define UD_DECODE_H
+
+#include "types.h"
+#include "udint.h"
+#include "itab.h"
+
+#define MAX_INSN_LENGTH 15
+
+/* itab prefix bits */
+#define P_none ( 0 )
+
+#define P_inv64 ( 1 << 0 )
+#define P_INV64(n) ( ( n >> 0 ) & 1 )
+#define P_def64 ( 1 << 1 )
+#define P_DEF64(n) ( ( n >> 1 ) & 1 )
+
+#define P_oso ( 1 << 2 )
+#define P_OSO(n) ( ( n >> 2 ) & 1 )
+#define P_aso ( 1 << 3 )
+#define P_ASO(n) ( ( n >> 3 ) & 1 )
+
+#define P_rexb ( 1 << 4 )
+#define P_REXB(n) ( ( n >> 4 ) & 1 )
+#define P_rexw ( 1 << 5 )
+#define P_REXW(n) ( ( n >> 5 ) & 1 )
+#define P_rexr ( 1 << 6 )
+#define P_REXR(n) ( ( n >> 6 ) & 1 )
+#define P_rexx ( 1 << 7 )
+#define P_REXX(n) ( ( n >> 7 ) & 1 )
+
+#define P_seg ( 1 << 8 )
+#define P_SEG(n) ( ( n >> 8 ) & 1 )
+
+#define P_vexl ( 1 << 9 )
+#define P_VEXL(n) ( ( n >> 9 ) & 1 )
+#define P_vexw ( 1 << 10 )
+#define P_VEXW(n) ( ( n >> 10 ) & 1 )
+
+#define P_str ( 1 << 11 )
+#define P_STR(n) ( ( n >> 11 ) & 1 )
+#define P_strz ( 1 << 12 )
+#define P_STR_ZF(n) ( ( n >> 12 ) & 1 )
+
+/* operand type constants -- order is important! */
+
+enum ud_operand_code {
+ OP_NONE,
+
+ OP_A, OP_E, OP_M, OP_G,
+ OP_I, OP_F,
+
+ OP_R0, OP_R1, OP_R2, OP_R3,
+ OP_R4, OP_R5, OP_R6, OP_R7,
+
+ OP_AL, OP_CL, OP_DL,
+ OP_AX, OP_CX, OP_DX,
+ OP_eAX, OP_eCX, OP_eDX,
+ OP_rAX, OP_rCX, OP_rDX,
+
+ OP_ES, OP_CS, OP_SS, OP_DS,
+ OP_FS, OP_GS,
+
+ OP_ST0, OP_ST1, OP_ST2, OP_ST3,
+ OP_ST4, OP_ST5, OP_ST6, OP_ST7,
+
+ OP_J, OP_S, OP_O,
+ OP_I1, OP_I3, OP_sI,
+
+ OP_V, OP_W, OP_Q, OP_P,
+ OP_U, OP_N, OP_MU, OP_H,
+ OP_L,
+
+ OP_R, OP_C, OP_D,
+
+ OP_MR
+} UD_ATTR_PACKED;
+
+
+/*
+ * Operand size constants
+ *
+ * Symbolic constants for various operand sizes. Some of these constants
+ * are given a value equal to the width of the data (SZ_B == 8), such
+ * that they maybe used interchangeably in the internals. Modifying them
+ * will most certainly break things!
+ */
+typedef uint16_t ud_operand_size_t;
+
+#define SZ_NA 0
+#define SZ_Z 1
+#define SZ_V 2
+#define SZ_Y 3
+#define SZ_X 4
+#define SZ_RDQ 7
+#define SZ_B 8
+#define SZ_W 16
+#define SZ_D 32
+#define SZ_Q 64
+#define SZ_T 80
+#define SZ_O 12
+#define SZ_DQ 128 /* double quad */
+#define SZ_QQ 256 /* quad quad */
+
+/*
+ * Complex size types; that encode sizes for operands of type MR (memory or
+ * register); for internal use only. Id space above 256.
+ */
+#define SZ_BD ((SZ_B << 8) | SZ_D)
+#define SZ_BV ((SZ_B << 8) | SZ_V)
+#define SZ_WD ((SZ_W << 8) | SZ_D)
+#define SZ_WV ((SZ_W << 8) | SZ_V)
+#define SZ_WY ((SZ_W << 8) | SZ_Y)
+#define SZ_DY ((SZ_D << 8) | SZ_Y)
+#define SZ_WO ((SZ_W << 8) | SZ_O)
+#define SZ_DO ((SZ_D << 8) | SZ_O)
+#define SZ_QO ((SZ_Q << 8) | SZ_O)
+
+
+/* resolve complex size type.
+ */
+static UD_INLINE ud_operand_size_t
+Mx_mem_size(ud_operand_size_t size)
+{
+ return (size >> 8) & 0xff;
+}
+
+static UD_INLINE ud_operand_size_t
+Mx_reg_size(ud_operand_size_t size)
+{
+ return size & 0xff;
+}
+
+/* A single operand of an entry in the instruction table.
+ * (internal use only)
+ */
+struct ud_itab_entry_operand
+{
+ enum ud_operand_code type;
+ ud_operand_size_t size;
+};
+
+
+/* A single entry in an instruction table.
+ *(internal use only)
+ */
+struct ud_itab_entry
+{
+ enum ud_mnemonic_code mnemonic;
+ struct ud_itab_entry_operand operand1;
+ struct ud_itab_entry_operand operand2;
+ struct ud_itab_entry_operand operand3;
+ struct ud_itab_entry_operand operand4;
+ uint32_t prefix;
+};
+
+struct ud_lookup_table_list_entry {
+ const uint16_t *table;
+ enum ud_table_type type;
+ const char *meta;
+};
+
+extern struct ud_itab_entry ud_itab[];
+extern struct ud_lookup_table_list_entry ud_lookup_table_list[];
+
+#endif /* UD_DECODE_H */
+
+/* vim:cindent
+ * vim:expandtab
+ * vim:ts=4
+ * vim:sw=4
+ */
diff --git a/ext/opcache/jit/libudis86/extern.h b/ext/opcache/jit/libudis86/extern.h
new file mode 100644
index 0000000000..71a01fd9b4
--- /dev/null
+++ b/ext/opcache/jit/libudis86/extern.h
@@ -0,0 +1,113 @@
+/* udis86 - libudis86/extern.h
+ *
+ * Copyright (c) 2002-2009, 2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_EXTERN_H
+#define UD_EXTERN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "types.h"
+
+#if defined(_MSC_VER) && defined(_USRDLL)
+# ifdef LIBUDIS86_EXPORTS
+# define LIBUDIS86_DLLEXTERN __declspec(dllexport)
+# else
+# define LIBUDIS86_DLLEXTERN __declspec(dllimport)
+# endif
+#else
+# define LIBUDIS86_DLLEXTERN
+#endif
+
+/* ============================= PUBLIC API ================================= */
+
+extern LIBUDIS86_DLLEXTERN void ud_init(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_mode(struct ud*, uint8_t);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_pc(struct ud*, uint64_t);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_input_hook(struct ud*, int (*)(struct ud*));
+
+extern LIBUDIS86_DLLEXTERN void ud_set_input_buffer(struct ud*, const uint8_t*, size_t);
+
+#ifndef __UD_STANDALONE__
+extern LIBUDIS86_DLLEXTERN void ud_set_input_file(struct ud*, FILE*);
+#endif /* __UD_STANDALONE__ */
+
+extern LIBUDIS86_DLLEXTERN void ud_set_vendor(struct ud*, unsigned);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_syntax(struct ud*, void (*)(struct ud*));
+
+extern LIBUDIS86_DLLEXTERN void ud_input_skip(struct ud*, size_t);
+
+extern LIBUDIS86_DLLEXTERN int ud_input_end(const struct ud*);
+
+extern LIBUDIS86_DLLEXTERN unsigned int ud_decode(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN unsigned int ud_disassemble(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_translate_intel(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_translate_att(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN const char* ud_insn_asm(const struct ud* u);
+
+extern LIBUDIS86_DLLEXTERN const uint8_t* ud_insn_ptr(const struct ud* u);
+
+extern LIBUDIS86_DLLEXTERN uint64_t ud_insn_off(const struct ud*);
+
+extern LIBUDIS86_DLLEXTERN const char* ud_insn_hex(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN unsigned int ud_insn_len(const struct ud* u);
+
+extern LIBUDIS86_DLLEXTERN const struct ud_operand* ud_insn_opr(const struct ud *u, unsigned int n);
+
+extern LIBUDIS86_DLLEXTERN int ud_opr_is_sreg(const struct ud_operand *opr);
+
+extern LIBUDIS86_DLLEXTERN int ud_opr_is_gpr(const struct ud_operand *opr);
+
+extern LIBUDIS86_DLLEXTERN enum ud_mnemonic_code ud_insn_mnemonic(const struct ud *u);
+
+extern LIBUDIS86_DLLEXTERN const char* ud_lookup_mnemonic(enum ud_mnemonic_code c);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_user_opaque_data(struct ud*, void*);
+
+extern LIBUDIS86_DLLEXTERN void* ud_get_user_opaque_data(const struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_asm_buffer(struct ud *u, char *buf, size_t size);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_sym_resolver(struct ud *u,
+ const char* (*resolver)(struct ud*,
+ uint64_t addr,
+ int64_t *offset));
+
+/* ========================================================================== */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* UD_EXTERN_H */
diff --git a/ext/opcache/jit/libudis86/itab.c b/ext/opcache/jit/libudis86/itab.c
new file mode 100644
index 0000000000..953f3e5227
--- /dev/null
+++ b/ext/opcache/jit/libudis86/itab.c
@@ -0,0 +1,5946 @@
+/* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */
+#include "decode.h"
+
+#define GROUP(n) (0x8000 | (n))
+#define INVALID 0
+
+
+const uint16_t ud_itab__0[] = {
+ /* 0 */ 15, 16, 17, 18,
+ /* 4 */ 19, 20, GROUP(1), GROUP(2),
+ /* 8 */ 964, 965, 966, 967,
+ /* c */ 968, 969, GROUP(3), GROUP(4),
+ /* 10 */ 5, 6, 7, 8,
+ /* 14 */ 9, 10, GROUP(284), GROUP(285),
+ /* 18 */ 1336, 1337, 1338, 1339,
+ /* 1c */ 1340, 1341, GROUP(286), GROUP(287),
+ /* 20 */ 49, 50, 51, 52,
+ /* 24 */ 53, 54, INVALID, GROUP(288),
+ /* 28 */ 1407, 1408, 1409, 1410,
+ /* 2c */ 1411, 1412, INVALID, GROUP(289),
+ /* 30 */ 1487, 1488, 1489, 1490,
+ /* 34 */ 1491, 1492, INVALID, GROUP(290),
+ /* 38 */ 100, 101, 102, 103,
+ /* 3c */ 104, 105, INVALID, GROUP(291),
+ /* 40 */ 699, 700, 701, 702,
+ /* 44 */ 703, 704, 705, 706,
+ /* 48 */ 175, 176, 177, 178,
+ /* 4c */ 179, 180, 181, 182,
+ /* 50 */ 1246, 1247, 1248, 1249,
+ /* 54 */ 1250, 1251, 1252, 1253,
+ /* 58 */ 1101, 1102, 1103, 1104,
+ /* 5c */ 1105, 1106, 1107, 1108,
+ /* 60 */ GROUP(292), GROUP(295), GROUP(298), GROUP(299),
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ 1254, 697, 1256, 698,
+ /* 6c */ 709, GROUP(300), 982, GROUP(301),
+ /* 70 */ 726, 728, 730, 732,
+ /* 74 */ 734, 736, 738, 740,
+ /* 78 */ 742, 744, 746, 748,
+ /* 7c */ 750, 752, 754, 756,
+ /* 80 */ GROUP(302), GROUP(303), GROUP(304), GROUP(313),
+ /* 84 */ 1433, 1434, 1475, 1476,
+ /* 88 */ 828, 829, 830, 831,
+ /* 8c */ 832, 770, 833, GROUP(314),
+ /* 90 */ 1477, 1478, 1479, 1480,
+ /* 94 */ 1481, 1482, 1483, 1484,
+ /* 98 */ GROUP(315), GROUP(316), GROUP(317), 1470,
+ /* 9c */ GROUP(318), GROUP(322), 1310, 766,
+ /* a0 */ 834, 835, 836, 837,
+ /* a4 */ 922, GROUP(326), 114, GROUP(327),
+ /* a8 */ 1435, 1436, 1402, GROUP(328),
+ /* ac */ 790, GROUP(329), 1346, GROUP(330),
+ /* b0 */ 838, 839, 840, 841,
+ /* b4 */ 842, 843, 844, 845,
+ /* b8 */ 846, 847, 848, 849,
+ /* bc */ 850, 851, 852, 853,
+ /* c0 */ GROUP(331), GROUP(332), 1301, 1302,
+ /* c4 */ GROUP(333), GROUP(403), GROUP(405), GROUP(406),
+ /* c8 */ 200, 776, 1303, 1304,
+ /* cc */ 713, 714, GROUP(407), GROUP(408),
+ /* d0 */ GROUP(409), GROUP(410), GROUP(411), GROUP(412),
+ /* d4 */ GROUP(413), GROUP(414), GROUP(415), 1486,
+ /* d8 */ GROUP(416), GROUP(419), GROUP(422), GROUP(425),
+ /* dc */ GROUP(428), GROUP(431), GROUP(434), GROUP(437),
+ /* e0 */ 794, 795, 796, GROUP(440),
+ /* e4 */ 690, 691, 978, 979,
+ /* e8 */ 72, 763, GROUP(441), 765,
+ /* ec */ 692, 693, 980, 981,
+ /* f0 */ 789, 712, 1299, 1300,
+ /* f4 */ 687, 83, GROUP(442), GROUP(443),
+ /* f8 */ 77, 1395, 81, 1398,
+ /* fc */ 78, 1396, GROUP(444), GROUP(445),
+};
+
+static const uint16_t ud_itab__1[] = {
+ /* 0 */ 1240, INVALID,
+};
+
+static const uint16_t ud_itab__2[] = {
+ /* 0 */ 1096, INVALID,
+};
+
+static const uint16_t ud_itab__3[] = {
+ /* 0 */ 1241, INVALID,
+};
+
+static const uint16_t ud_itab__4[] = {
+ /* 0 */ GROUP(5), GROUP(6), 767, 797,
+ /* 4 */ INVALID, 1426, 82, 1431,
+ /* 8 */ 716, 1471, INVALID, 1444,
+ /* c */ INVALID, GROUP(27), 430, GROUP(28),
+ /* 10 */ GROUP(29), GROUP(30), GROUP(31), GROUP(34),
+ /* 14 */ GROUP(35), GROUP(36), GROUP(37), GROUP(40),
+ /* 18 */ GROUP(41), 955, 956, 957,
+ /* 1c */ 958, 959, 960, 961,
+ /* 20 */ 854, 855, 856, 857,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ GROUP(42), GROUP(43), GROUP(44), GROUP(45),
+ /* 2c */ GROUP(46), GROUP(47), GROUP(48), GROUP(49),
+ /* 30 */ 1472, 1297, 1295, 1296,
+ /* 34 */ GROUP(50), GROUP(52), INVALID, 1514,
+ /* 38 */ GROUP(54), INVALID, GROUP(116), INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ 84, 85, 86, 87,
+ /* 44 */ 88, 89, 90, 91,
+ /* 48 */ 92, 93, 94, 95,
+ /* 4c */ 96, 97, 98, 99,
+ /* 50 */ GROUP(143), GROUP(144), GROUP(145), GROUP(146),
+ /* 54 */ GROUP(147), GROUP(148), GROUP(149), GROUP(150),
+ /* 58 */ GROUP(151), GROUP(152), GROUP(153), GROUP(154),
+ /* 5c */ GROUP(155), GROUP(156), GROUP(157), GROUP(158),
+ /* 60 */ GROUP(159), GROUP(160), GROUP(161), GROUP(162),
+ /* 64 */ GROUP(163), GROUP(164), GROUP(165), GROUP(166),
+ /* 68 */ GROUP(167), GROUP(168), GROUP(169), GROUP(170),
+ /* 6c */ GROUP(171), GROUP(172), GROUP(173), GROUP(176),
+ /* 70 */ GROUP(177), GROUP(178), GROUP(182), GROUP(186),
+ /* 74 */ GROUP(191), GROUP(192), GROUP(193), 199,
+ /* 78 */ GROUP(194), GROUP(195), INVALID, INVALID,
+ /* 7c */ GROUP(196), GROUP(197), GROUP(198), GROUP(201),
+ /* 80 */ 727, 729, 731, 733,
+ /* 84 */ 735, 737, 739, 741,
+ /* 88 */ 743, 745, 747, 749,
+ /* 8c */ 751, 753, 755, 757,
+ /* 90 */ 1350, 1351, 1352, 1353,
+ /* 94 */ 1354, 1355, 1356, 1357,
+ /* 98 */ 1358, 1359, 1360, 1361,
+ /* 9c */ 1362, 1363, 1364, 1365,
+ /* a0 */ 1245, 1100, 131, 1670,
+ /* a4 */ 1375, 1376, GROUP(202), GROUP(207),
+ /* a8 */ 1244, 1099, 1305, 1675,
+ /* ac */ 1377, 1378, GROUP(215), 694,
+ /* b0 */ 122, 123, 775, 1673,
+ /* b4 */ 772, 773, 940, 941,
+ /* b8 */ GROUP(221), INVALID, GROUP(222), 1671,
+ /* bc */ 1659, 1660, 930, 931,
+ /* c0 */ 1473, 1474, GROUP(223), 904,
+ /* c4 */ GROUP(224), GROUP(225), GROUP(226), GROUP(227),
+ /* c8 */ 1661, 1662, 1663, 1664,
+ /* cc */ 1665, 1666, 1667, 1668,
+ /* d0 */ GROUP(236), GROUP(237), GROUP(238), GROUP(239),
+ /* d4 */ GROUP(240), GROUP(241), GROUP(242), GROUP(243),
+ /* d8 */ GROUP(244), GROUP(245), GROUP(246), GROUP(247),
+ /* dc */ GROUP(248), GROUP(249), GROUP(250), GROUP(251),
+ /* e0 */ GROUP(252), GROUP(253), GROUP(254), GROUP(255),
+ /* e4 */ GROUP(256), GROUP(257), GROUP(258), GROUP(259),
+ /* e8 */ GROUP(260), GROUP(261), GROUP(262), GROUP(263),
+ /* ec */ GROUP(264), GROUP(265), GROUP(266), GROUP(267),
+ /* f0 */ GROUP(268), GROUP(269), GROUP(270), GROUP(271),
+ /* f4 */ GROUP(272), GROUP(273), GROUP(274), GROUP(275),
+ /* f8 */ GROUP(277), GROUP(278), GROUP(279), GROUP(280),
+ /* fc */ GROUP(281), GROUP(282), GROUP(283), INVALID,
+};
+
+static const uint16_t ud_itab__5[] = {
+ /* 0 */ 1384, 1406, 786, 798,
+ /* 4 */ 1453, 1454, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__6[] = {
+ /* 0 */ GROUP(7), GROUP(8),
+};
+
+static const uint16_t ud_itab__7[] = {
+ /* 0 */ 1374, 1383, 785, 774,
+ /* 4 */ 1385, INVALID, 787, 719,
+};
+
+static const uint16_t ud_itab__8[] = {
+ /* 0 */ GROUP(9), GROUP(14), GROUP(15), GROUP(16),
+ /* 4 */ 1386, INVALID, 788, GROUP(25),
+};
+
+static const uint16_t ud_itab__9[] = {
+ /* 0 */ INVALID, GROUP(10), GROUP(11), GROUP(12),
+ /* 4 */ GROUP(13), INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__10[] = {
+ /* 0 */ INVALID, 1455, INVALID,
+};
+
+static const uint16_t ud_itab__11[] = {
+ /* 0 */ INVALID, 1461, INVALID,
+};
+
+static const uint16_t ud_itab__12[] = {
+ /* 0 */ INVALID, 1462, INVALID,
+};
+
+static const uint16_t ud_itab__13[] = {
+ /* 0 */ INVALID, 1463, INVALID,
+};
+
+static const uint16_t ud_itab__14[] = {
+ /* 0 */ 824, 952, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__15[] = {
+ /* 0 */ 1485, 1508, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__16[] = {
+ /* 0 */ GROUP(17), GROUP(18), GROUP(19), GROUP(20),
+ /* 4 */ GROUP(21), GROUP(22), GROUP(23), GROUP(24),
+};
+
+static const uint16_t ud_itab__17[] = {
+ /* 0 */ 1466, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__18[] = {
+ /* 0 */ 1467, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__19[] = {
+ /* 0 */ 1468, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__20[] = {
+ /* 0 */ 1469, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__21[] = {
+ /* 0 */ 1397, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__22[] = {
+ /* 0 */ 80, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__23[] = {
+ /* 0 */ 1399, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__24[] = {
+ /* 0 */ 720, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__25[] = {
+ /* 0 */ 1425, GROUP(26), INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__26[] = {
+ /* 0 */ 1298, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__27[] = {
+ /* 0 */ 1119, 1120, 1121, 1122,
+ /* 4 */ 1123, 1124, 1125, 1126,
+};
+
+static const uint16_t ud_itab__28[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ 1216, 1217, INVALID, INVALID,
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, INVALID,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ 1218, 1219, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, 1220, INVALID,
+ /* 8c */ INVALID, INVALID, 1221, INVALID,
+ /* 90 */ 1222, INVALID, INVALID, INVALID,
+ /* 94 */ 1223, INVALID, 1224, 1225,
+ /* 98 */ INVALID, INVALID, 1226, INVALID,
+ /* 9c */ INVALID, INVALID, 1227, INVALID,
+ /* a0 */ 1228, INVALID, INVALID, INVALID,
+ /* a4 */ 1229, INVALID, 1230, 1231,
+ /* a8 */ INVALID, INVALID, 1232, INVALID,
+ /* ac */ INVALID, INVALID, 1233, INVALID,
+ /* b0 */ 1234, INVALID, INVALID, INVALID,
+ /* b4 */ 1235, INVALID, 1236, 1237,
+ /* b8 */ INVALID, INVALID, INVALID, 1238,
+ /* bc */ INVALID, INVALID, INVALID, 1239,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__29[] = {
+ /* 0 */ 936, 925, 928, 932,
+};
+
+static const uint16_t ud_itab__30[] = {
+ /* 0 */ 938, 926, 929, 934,
+};
+
+static const uint16_t ud_itab__31[] = {
+ /* 0 */ GROUP(32), GROUP(33),
+};
+
+static const uint16_t ud_itab__32[] = {
+ /* 0 */ 892, 1563, 1571, 888,
+};
+
+static const uint16_t ud_itab__33[] = {
+ /* 0 */ 896, 1561, 1569, INVALID,
+};
+
+static const uint16_t ud_itab__34[] = {
+ /* 0 */ 894, INVALID, INVALID, 890,
+};
+
+static const uint16_t ud_itab__35[] = {
+ /* 0 */ 1449, INVALID, INVALID, 1451,
+};
+
+static const uint16_t ud_itab__36[] = {
+ /* 0 */ 1447, INVALID, INVALID, 1445,
+};
+
+static const uint16_t ud_itab__37[] = {
+ /* 0 */ GROUP(38), GROUP(39),
+};
+
+static const uint16_t ud_itab__38[] = {
+ /* 0 */ 882, INVALID, 1567, 878,
+};
+
+static const uint16_t ud_itab__39[] = {
+ /* 0 */ 886, INVALID, 1565, INVALID,
+};
+
+static const uint16_t ud_itab__40[] = {
+ /* 0 */ 884, INVALID, INVALID, 880,
+};
+
+static const uint16_t ud_itab__41[] = {
+ /* 0 */ 1127, 1128, 1129, 1130,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__42[] = {
+ /* 0 */ 862, INVALID, INVALID, 858,
+};
+
+static const uint16_t ud_itab__43[] = {
+ /* 0 */ 864, INVALID, INVALID, 860,
+};
+
+static const uint16_t ud_itab__44[] = {
+ /* 0 */ 141, 152, 154, 142,
+};
+
+static const uint16_t ud_itab__45[] = {
+ /* 0 */ 907, INVALID, INVALID, 905,
+};
+
+static const uint16_t ud_itab__46[] = {
+ /* 0 */ 165, 166, 168, 162,
+};
+
+static const uint16_t ud_itab__47[] = {
+ /* 0 */ 147, 148, 158, 138,
+};
+
+static const uint16_t ud_itab__48[] = {
+ /* 0 */ 1442, INVALID, INVALID, 1440,
+};
+
+static const uint16_t ud_itab__49[] = {
+ /* 0 */ 129, INVALID, INVALID, 127,
+};
+
+static const uint16_t ud_itab__50[] = {
+ /* 0 */ 1427, GROUP(51),
+};
+
+static const uint16_t ud_itab__51[] = {
+ /* 0 */ INVALID, 1428, INVALID,
+};
+
+static const uint16_t ud_itab__52[] = {
+ /* 0 */ 1429, GROUP(53),
+};
+
+static const uint16_t ud_itab__53[] = {
+ /* 0 */ INVALID, 1430, INVALID,
+};
+
+static const uint16_t ud_itab__54[] = {
+ /* 0 */ GROUP(67), GROUP(68), GROUP(63), GROUP(64),
+ /* 4 */ GROUP(65), GROUP(66), GROUP(86), GROUP(90),
+ /* 8 */ GROUP(69), GROUP(70), GROUP(71), GROUP(72),
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ GROUP(73), INVALID, INVALID, INVALID,
+ /* 14 */ GROUP(75), GROUP(76), INVALID, GROUP(77),
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ GROUP(78), GROUP(79), GROUP(80), INVALID,
+ /* 20 */ GROUP(81), GROUP(82), GROUP(83), GROUP(84),
+ /* 24 */ GROUP(85), GROUP(108), INVALID, INVALID,
+ /* 28 */ GROUP(87), GROUP(88), GROUP(89), GROUP(74),
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ GROUP(91), GROUP(92), GROUP(93), GROUP(94),
+ /* 34 */ GROUP(95), GROUP(96), INVALID, GROUP(97),
+ /* 38 */ GROUP(98), GROUP(99), GROUP(100), GROUP(101),
+ /* 3c */ GROUP(102), GROUP(103), GROUP(104), GROUP(105),
+ /* 40 */ GROUP(106), GROUP(107), INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ GROUP(55), GROUP(59), INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, GROUP(109),
+ /* dc */ GROUP(110), GROUP(111), GROUP(112), GROUP(113),
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ GROUP(114), GROUP(115), INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__55[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(56),
+};
+
+static const uint16_t ud_itab__56[] = {
+ /* 0 */ GROUP(57), GROUP(58),
+};
+
+static const uint16_t ud_itab__57[] = {
+ /* 0 */ INVALID, 717, INVALID,
+};
+
+static const uint16_t ud_itab__58[] = {
+ /* 0 */ INVALID, 718, INVALID,
+};
+
+static const uint16_t ud_itab__59[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(60),
+};
+
+static const uint16_t ud_itab__60[] = {
+ /* 0 */ GROUP(61), GROUP(62),
+};
+
+static const uint16_t ud_itab__61[] = {
+ /* 0 */ INVALID, 721, INVALID,
+};
+
+static const uint16_t ud_itab__62[] = {
+ /* 0 */ INVALID, 722, INVALID,
+};
+
+static const uint16_t ud_itab__63[] = {
+ /* 0 */ 1588, INVALID, INVALID, 1589,
+};
+
+static const uint16_t ud_itab__64[] = {
+ /* 0 */ 1591, INVALID, INVALID, 1592,
+};
+
+static const uint16_t ud_itab__65[] = {
+ /* 0 */ 1594, INVALID, INVALID, 1595,
+};
+
+static const uint16_t ud_itab__66[] = {
+ /* 0 */ 1597, INVALID, INVALID, 1598,
+};
+
+static const uint16_t ud_itab__67[] = {
+ /* 0 */ 1582, INVALID, INVALID, 1583,
+};
+
+static const uint16_t ud_itab__68[] = {
+ /* 0 */ 1585, INVALID, INVALID, 1586,
+};
+
+static const uint16_t ud_itab__69[] = {
+ /* 0 */ 1606, INVALID, INVALID, 1607,
+};
+
+static const uint16_t ud_itab__70[] = {
+ /* 0 */ 1612, INVALID, INVALID, 1613,
+};
+
+static const uint16_t ud_itab__71[] = {
+ /* 0 */ 1609, INVALID, INVALID, 1610,
+};
+
+static const uint16_t ud_itab__72[] = {
+ /* 0 */ 1615, INVALID, INVALID, 1616,
+};
+
+static const uint16_t ud_itab__73[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1621,
+};
+
+static const uint16_t ud_itab__74[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1683,
+};
+
+static const uint16_t ud_itab__75[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1657,
+};
+
+static const uint16_t ud_itab__76[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1656,
+};
+
+static const uint16_t ud_itab__77[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1711,
+};
+
+static const uint16_t ud_itab__78[] = {
+ /* 0 */ 1573, INVALID, INVALID, 1574,
+};
+
+static const uint16_t ud_itab__79[] = {
+ /* 0 */ 1576, INVALID, INVALID, 1577,
+};
+
+static const uint16_t ud_itab__80[] = {
+ /* 0 */ 1579, INVALID, INVALID, 1580,
+};
+
+static const uint16_t ud_itab__81[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1685,
+};
+
+static const uint16_t ud_itab__82[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1687,
+};
+
+static const uint16_t ud_itab__83[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1689,
+};
+
+static const uint16_t ud_itab__84[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1691,
+};
+
+static const uint16_t ud_itab__85[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1693,
+};
+
+static const uint16_t ud_itab__86[] = {
+ /* 0 */ 1600, INVALID, INVALID, 1601,
+};
+
+static const uint16_t ud_itab__87[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1622,
+};
+
+static const uint16_t ud_itab__88[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1708,
+};
+
+static const uint16_t ud_itab__89[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1681,
+};
+
+static const uint16_t ud_itab__90[] = {
+ /* 0 */ 1603, INVALID, INVALID, 1604,
+};
+
+static const uint16_t ud_itab__91[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1696,
+};
+
+static const uint16_t ud_itab__92[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1698,
+};
+
+static const uint16_t ud_itab__93[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1700,
+};
+
+static const uint16_t ud_itab__94[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1702,
+};
+
+static const uint16_t ud_itab__95[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1704,
+};
+
+static const uint16_t ud_itab__96[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1706,
+};
+
+static const uint16_t ud_itab__97[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1717,
+};
+
+static const uint16_t ud_itab__98[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1624,
+};
+
+static const uint16_t ud_itab__99[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1626,
+};
+
+static const uint16_t ud_itab__100[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1628,
+};
+
+static const uint16_t ud_itab__101[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1630,
+};
+
+static const uint16_t ud_itab__102[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1632,
+};
+
+static const uint16_t ud_itab__103[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1634,
+};
+
+static const uint16_t ud_itab__104[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1638,
+};
+
+static const uint16_t ud_itab__105[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1636,
+};
+
+static const uint16_t ud_itab__106[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1640,
+};
+
+static const uint16_t ud_itab__107[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1642,
+};
+
+static const uint16_t ud_itab__108[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1695,
+};
+
+static const uint16_t ud_itab__109[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 45,
+};
+
+static const uint16_t ud_itab__110[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 41,
+};
+
+static const uint16_t ud_itab__111[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 43,
+};
+
+static const uint16_t ud_itab__112[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 37,
+};
+
+static const uint16_t ud_itab__113[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 39,
+};
+
+static const uint16_t ud_itab__114[] = {
+ /* 0 */ 1723, 1725, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__115[] = {
+ /* 0 */ 1724, 1726, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__116[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ GROUP(117), GROUP(118), GROUP(119), GROUP(120),
+ /* c */ GROUP(121), GROUP(122), GROUP(123), GROUP(124),
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ GROUP(125), GROUP(126), GROUP(127), GROUP(129),
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ GROUP(130), GROUP(131), GROUP(132), INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ GROUP(134), GROUP(135), GROUP(136), INVALID,
+ /* 44 */ GROUP(137), INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ GROUP(139), GROUP(140), GROUP(141), GROUP(142),
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, GROUP(138),
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__117[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1644,
+};
+
+static const uint16_t ud_itab__118[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1646,
+};
+
+static const uint16_t ud_itab__119[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1648,
+};
+
+static const uint16_t ud_itab__120[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1650,
+};
+
+static const uint16_t ud_itab__121[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1654,
+};
+
+static const uint16_t ud_itab__122[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1652,
+};
+
+static const uint16_t ud_itab__123[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1677,
+};
+
+static const uint16_t ud_itab__124[] = {
+ /* 0 */ 1618, INVALID, INVALID, 1619,
+};
+
+static const uint16_t ud_itab__125[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1045,
+};
+
+static const uint16_t ud_itab__126[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1056,
+};
+
+static const uint16_t ud_itab__127[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(128),
+};
+
+static const uint16_t ud_itab__128[] = {
+ /* 0 */ 1047, 1049, 1051,
+};
+
+static const uint16_t ud_itab__129[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 201,
+};
+
+static const uint16_t ud_itab__130[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1058,
+};
+
+static const uint16_t ud_itab__131[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1557,
+};
+
+static const uint16_t ud_itab__132[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(133),
+};
+
+static const uint16_t ud_itab__133[] = {
+ /* 0 */ 1062, 1063, 1064,
+};
+
+static const uint16_t ud_itab__134[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 197,
+};
+
+static const uint16_t ud_itab__135[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 195,
+};
+
+static const uint16_t ud_itab__136[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1679,
+};
+
+static const uint16_t ud_itab__137[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1512,
+};
+
+static const uint16_t ud_itab__138[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 47,
+};
+
+static const uint16_t ud_itab__139[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1715,
+};
+
+static const uint16_t ud_itab__140[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1713,
+};
+
+static const uint16_t ud_itab__141[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1721,
+};
+
+static const uint16_t ud_itab__142[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1719,
+};
+
+static const uint16_t ud_itab__143[] = {
+ /* 0 */ 900, INVALID, INVALID, 898,
+};
+
+static const uint16_t ud_itab__144[] = {
+ /* 0 */ 1387, 1391, 1393, 1389,
+};
+
+static const uint16_t ud_itab__145[] = {
+ /* 0 */ 1306, INVALID, 1308, INVALID,
+};
+
+static const uint16_t ud_itab__146[] = {
+ /* 0 */ 1291, INVALID, 1293, INVALID,
+};
+
+static const uint16_t ud_itab__147[] = {
+ /* 0 */ 61, INVALID, INVALID, 59,
+};
+
+static const uint16_t ud_itab__148[] = {
+ /* 0 */ 65, INVALID, INVALID, 63,
+};
+
+static const uint16_t ud_itab__149[] = {
+ /* 0 */ 976, INVALID, INVALID, 974,
+};
+
+static const uint16_t ud_itab__150[] = {
+ /* 0 */ 1499, INVALID, INVALID, 1497,
+};
+
+static const uint16_t ud_itab__151[] = {
+ /* 0 */ 27, 29, 31, 25,
+};
+
+static const uint16_t ud_itab__152[] = {
+ /* 0 */ 946, 948, 950, 944,
+};
+
+static const uint16_t ud_itab__153[] = {
+ /* 0 */ 145, 150, 156, 139,
+};
+
+static const uint16_t ud_itab__154[] = {
+ /* 0 */ 134, INVALID, 163, 143,
+};
+
+static const uint16_t ud_itab__155[] = {
+ /* 0 */ 1419, 1421, 1423, 1417,
+};
+
+static const uint16_t ud_itab__156[] = {
+ /* 0 */ 818, 820, 822, 816,
+};
+
+static const uint16_t ud_itab__157[] = {
+ /* 0 */ 189, 191, 193, 187,
+};
+
+static const uint16_t ud_itab__158[] = {
+ /* 0 */ 802, 804, 806, 800,
+};
+
+static const uint16_t ud_itab__159[] = {
+ /* 0 */ 1209, INVALID, INVALID, 1207,
+};
+
+static const uint16_t ud_itab__160[] = {
+ /* 0 */ 1212, INVALID, INVALID, 1210,
+};
+
+static const uint16_t ud_itab__161[] = {
+ /* 0 */ 1215, INVALID, INVALID, 1213,
+};
+
+static const uint16_t ud_itab__162[] = {
+ /* 0 */ 987, INVALID, INVALID, 985,
+};
+
+static const uint16_t ud_itab__163[] = {
+ /* 0 */ 1038, INVALID, INVALID, 1036,
+};
+
+static const uint16_t ud_itab__164[] = {
+ /* 0 */ 1041, INVALID, INVALID, 1039,
+};
+
+static const uint16_t ud_itab__165[] = {
+ /* 0 */ 1044, INVALID, INVALID, 1042,
+};
+
+static const uint16_t ud_itab__166[] = {
+ /* 0 */ 993, INVALID, INVALID, 991,
+};
+
+static const uint16_t ud_itab__167[] = {
+ /* 0 */ 1200, INVALID, INVALID, 1198,
+};
+
+static const uint16_t ud_itab__168[] = {
+ /* 0 */ 1203, INVALID, INVALID, 1201,
+};
+
+static const uint16_t ud_itab__169[] = {
+ /* 0 */ 1206, INVALID, INVALID, 1204,
+};
+
+static const uint16_t ud_itab__170[] = {
+ /* 0 */ 990, INVALID, INVALID, 988,
+};
+
+static const uint16_t ud_itab__171[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1547,
+};
+
+static const uint16_t ud_itab__172[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1545,
+};
+
+static const uint16_t ud_itab__173[] = {
+ /* 0 */ GROUP(174), INVALID, INVALID, GROUP(175),
+};
+
+static const uint16_t ud_itab__174[] = {
+ /* 0 */ 866, 867, 910,
+};
+
+static const uint16_t ud_itab__175[] = {
+ /* 0 */ 868, 870, 911,
+};
+
+static const uint16_t ud_itab__176[] = {
+ /* 0 */ 920, INVALID, 1522, 1517,
+};
+
+static const uint16_t ud_itab__177[] = {
+ /* 0 */ 1134, 1537, 1535, 1539,
+};
+
+static const uint16_t ud_itab__178[] = {
+ /* 0 */ INVALID, INVALID, GROUP(179), INVALID,
+ /* 4 */ GROUP(180), INVALID, GROUP(181), INVALID,
+};
+
+static const uint16_t ud_itab__179[] = {
+ /* 0 */ 1159, INVALID, INVALID, 1163,
+};
+
+static const uint16_t ud_itab__180[] = {
+ /* 0 */ 1152, INVALID, INVALID, 1150,
+};
+
+static const uint16_t ud_itab__181[] = {
+ /* 0 */ 1138, INVALID, INVALID, 1137,
+};
+
+static const uint16_t ud_itab__182[] = {
+ /* 0 */ INVALID, INVALID, GROUP(183), INVALID,
+ /* 4 */ GROUP(184), INVALID, GROUP(185), INVALID,
+};
+
+static const uint16_t ud_itab__183[] = {
+ /* 0 */ 1165, INVALID, INVALID, 1169,
+};
+
+static const uint16_t ud_itab__184[] = {
+ /* 0 */ 1153, INVALID, INVALID, 1157,
+};
+
+static const uint16_t ud_itab__185[] = {
+ /* 0 */ 1142, INVALID, INVALID, 1141,
+};
+
+static const uint16_t ud_itab__186[] = {
+ /* 0 */ INVALID, INVALID, GROUP(187), GROUP(188),
+ /* 4 */ INVALID, INVALID, GROUP(189), GROUP(190),
+};
+
+static const uint16_t ud_itab__187[] = {
+ /* 0 */ 1171, INVALID, INVALID, 1175,
+};
+
+static const uint16_t ud_itab__188[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1543,
+};
+
+static const uint16_t ud_itab__189[] = {
+ /* 0 */ 1146, INVALID, INVALID, 1145,
+};
+
+static const uint16_t ud_itab__190[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1541,
+};
+
+static const uint16_t ud_itab__191[] = {
+ /* 0 */ 1027, INVALID, INVALID, 1028,
+};
+
+static const uint16_t ud_itab__192[] = {
+ /* 0 */ 1030, INVALID, INVALID, 1031,
+};
+
+static const uint16_t ud_itab__193[] = {
+ /* 0 */ 1033, INVALID, INVALID, 1034,
+};
+
+static const uint16_t ud_itab__194[] = {
+ /* 0 */ INVALID, 1464, INVALID,
+};
+
+static const uint16_t ud_itab__195[] = {
+ /* 0 */ INVALID, 1465, INVALID,
+};
+
+static const uint16_t ud_itab__196[] = {
+ /* 0 */ INVALID, 1551, INVALID, 1549,
+};
+
+static const uint16_t ud_itab__197[] = {
+ /* 0 */ INVALID, 1555, INVALID, 1553,
+};
+
+static const uint16_t ud_itab__198[] = {
+ /* 0 */ GROUP(199), INVALID, 916, GROUP(200),
+};
+
+static const uint16_t ud_itab__199[] = {
+ /* 0 */ 872, 873, 913,
+};
+
+static const uint16_t ud_itab__200[] = {
+ /* 0 */ 874, 876, 914,
+};
+
+static const uint16_t ud_itab__201[] = {
+ /* 0 */ 921, INVALID, 1524, 1515,
+};
+
+static const uint16_t ud_itab__202[] = {
+ /* 0 */ INVALID, GROUP(203),
+};
+
+static const uint16_t ud_itab__203[] = {
+ /* 0 */ GROUP(204), GROUP(205), GROUP(206), INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__204[] = {
+ /* 0 */ 825, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__205[] = {
+ /* 0 */ 1509, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__206[] = {
+ /* 0 */ 1510, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__207[] = {
+ /* 0 */ INVALID, GROUP(208),
+};
+
+static const uint16_t ud_itab__208[] = {
+ /* 0 */ GROUP(209), GROUP(210), GROUP(211), GROUP(212),
+ /* 4 */ GROUP(213), GROUP(214), INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__209[] = {
+ /* 0 */ 1511, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__210[] = {
+ /* 0 */ 1501, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__211[] = {
+ /* 0 */ 1502, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__212[] = {
+ /* 0 */ 1503, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__213[] = {
+ /* 0 */ 1504, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__214[] = {
+ /* 0 */ 1505, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__215[] = {
+ /* 0 */ GROUP(216), GROUP(217),
+};
+
+static const uint16_t ud_itab__216[] = {
+ /* 0 */ 683, 682, 768, 1400,
+ /* 4 */ 1507, 1506, INVALID, 79,
+};
+
+static const uint16_t ud_itab__217[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, GROUP(218), GROUP(219), GROUP(220),
+};
+
+static const uint16_t ud_itab__218[] = {
+ /* 0 */ 777, 778, 779, 780,
+ /* 4 */ 781, 782, 783, 784,
+};
+
+static const uint16_t ud_itab__219[] = {
+ /* 0 */ 808, 809, 810, 811,
+ /* 4 */ 812, 813, 814, 815,
+};
+
+static const uint16_t ud_itab__220[] = {
+ /* 0 */ 1366, 1367, 1368, 1369,
+ /* 4 */ 1370, 1371, 1372, 1373,
+};
+
+static const uint16_t ud_itab__221[] = {
+ /* 0 */ INVALID, INVALID, 1710, INVALID,
+};
+
+static const uint16_t ud_itab__222[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ 1669, 1676, 1674, 1672,
+};
+
+static const uint16_t ud_itab__223[] = {
+ /* 0 */ 112, 117, 120, 110,
+};
+
+static const uint16_t ud_itab__224[] = {
+ /* 0 */ 1059, INVALID, INVALID, 1060,
+};
+
+static const uint16_t ud_itab__225[] = {
+ /* 0 */ 1055, INVALID, INVALID, 1053,
+};
+
+static const uint16_t ud_itab__226[] = {
+ /* 0 */ 1381, INVALID, INVALID, 1379,
+};
+
+static const uint16_t ud_itab__227[] = {
+ /* 0 */ GROUP(228), GROUP(235),
+};
+
+static const uint16_t ud_itab__228[] = {
+ /* 0 */ INVALID, GROUP(229), INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, GROUP(230), GROUP(234),
+};
+
+static const uint16_t ud_itab__229[] = {
+ /* 0 */ 124, 125, 126,
+};
+
+static const uint16_t ud_itab__230[] = {
+ /* 0 */ GROUP(231), INVALID, GROUP(232), GROUP(233),
+};
+
+static const uint16_t ud_itab__231[] = {
+ /* 0 */ INVALID, 1459, INVALID,
+};
+
+static const uint16_t ud_itab__232[] = {
+ /* 0 */ INVALID, 1458, INVALID,
+};
+
+static const uint16_t ud_itab__233[] = {
+ /* 0 */ INVALID, 1457, INVALID,
+};
+
+static const uint16_t ud_itab__234[] = {
+ /* 0 */ INVALID, 1460, INVALID,
+};
+
+static const uint16_t ud_itab__235[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, 1456, INVALID,
+};
+
+static const uint16_t ud_itab__236[] = {
+ /* 0 */ INVALID, 35, INVALID, 33,
+};
+
+static const uint16_t ud_itab__237[] = {
+ /* 0 */ 1160, INVALID, INVALID, 1161,
+};
+
+static const uint16_t ud_itab__238[] = {
+ /* 0 */ 1166, INVALID, INVALID, 1167,
+};
+
+static const uint16_t ud_itab__239[] = {
+ /* 0 */ 1172, INVALID, INVALID, 1173,
+};
+
+static const uint16_t ud_itab__240[] = {
+ /* 0 */ 1527, INVALID, INVALID, 1528,
+};
+
+static const uint16_t ud_itab__241[] = {
+ /* 0 */ 1093, INVALID, INVALID, 1094,
+};
+
+static const uint16_t ud_itab__242[] = {
+ /* 0 */ INVALID, 1521, 1526, 918,
+};
+
+static const uint16_t ud_itab__243[] = {
+ /* 0 */ 1086, INVALID, INVALID, 1084,
+};
+
+static const uint16_t ud_itab__244[] = {
+ /* 0 */ 1192, INVALID, INVALID, 1193,
+};
+
+static const uint16_t ud_itab__245[] = {
+ /* 0 */ 1195, INVALID, INVALID, 1196,
+};
+
+static const uint16_t ud_itab__246[] = {
+ /* 0 */ 1083, INVALID, INVALID, 1081,
+};
+
+static const uint16_t ud_itab__247[] = {
+ /* 0 */ 1017, INVALID, INVALID, 1015,
+};
+
+static const uint16_t ud_itab__248[] = {
+ /* 0 */ 1009, INVALID, INVALID, 1010,
+};
+
+static const uint16_t ud_itab__249[] = {
+ /* 0 */ 1012, INVALID, INVALID, 1013,
+};
+
+static const uint16_t ud_itab__250[] = {
+ /* 0 */ 1075, INVALID, INVALID, 1076,
+};
+
+static const uint16_t ud_itab__251[] = {
+ /* 0 */ 1020, INVALID, INVALID, 1018,
+};
+
+static const uint16_t ud_itab__252[] = {
+ /* 0 */ 1023, INVALID, INVALID, 1021,
+};
+
+static const uint16_t ud_itab__253[] = {
+ /* 0 */ 1147, INVALID, INVALID, 1148,
+};
+
+static const uint16_t ud_itab__254[] = {
+ /* 0 */ 1156, INVALID, INVALID, 1154,
+};
+
+static const uint16_t ud_itab__255[] = {
+ /* 0 */ 1026, INVALID, INVALID, 1024,
+};
+
+static const uint16_t ud_itab__256[] = {
+ /* 0 */ 1087, INVALID, INVALID, 1088,
+};
+
+static const uint16_t ud_itab__257[] = {
+ /* 0 */ 1092, INVALID, INVALID, 1090,
+};
+
+static const uint16_t ud_itab__258[] = {
+ /* 0 */ INVALID, 136, 132, 160,
+};
+
+static const uint16_t ud_itab__259[] = {
+ /* 0 */ 909, INVALID, INVALID, 902,
+};
+
+static const uint16_t ud_itab__260[] = {
+ /* 0 */ 1186, INVALID, INVALID, 1187,
+};
+
+static const uint16_t ud_itab__261[] = {
+ /* 0 */ 1189, INVALID, INVALID, 1190,
+};
+
+static const uint16_t ud_itab__262[] = {
+ /* 0 */ 1080, INVALID, INVALID, 1078,
+};
+
+static const uint16_t ud_itab__263[] = {
+ /* 0 */ 1118, INVALID, INVALID, 1116,
+};
+
+static const uint16_t ud_itab__264[] = {
+ /* 0 */ 1003, INVALID, INVALID, 1004,
+};
+
+static const uint16_t ud_itab__265[] = {
+ /* 0 */ 1006, INVALID, INVALID, 1007,
+};
+
+static const uint16_t ud_itab__266[] = {
+ /* 0 */ 1074, INVALID, INVALID, 1072,
+};
+
+static const uint16_t ud_itab__267[] = {
+ /* 0 */ 1266, INVALID, INVALID, 1264,
+};
+
+static const uint16_t ud_itab__268[] = {
+ /* 0 */ INVALID, 1559, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__269[] = {
+ /* 0 */ 1136, INVALID, INVALID, 1135,
+};
+
+static const uint16_t ud_itab__270[] = {
+ /* 0 */ 1140, INVALID, INVALID, 1139,
+};
+
+static const uint16_t ud_itab__271[] = {
+ /* 0 */ 1144, INVALID, INVALID, 1143,
+};
+
+static const uint16_t ud_itab__272[] = {
+ /* 0 */ 1533, INVALID, INVALID, 1534,
+};
+
+static const uint16_t ud_itab__273[] = {
+ /* 0 */ 1069, INVALID, INVALID, 1070,
+};
+
+static const uint16_t ud_itab__274[] = {
+ /* 0 */ 1133, INVALID, INVALID, 1131,
+};
+
+static const uint16_t ud_itab__275[] = {
+ /* 0 */ INVALID, GROUP(276),
+};
+
+static const uint16_t ud_itab__276[] = {
+ /* 0 */ 799, INVALID, INVALID, 1519,
+};
+
+static const uint16_t ud_itab__277[] = {
+ /* 0 */ 1179, INVALID, INVALID, 1177,
+};
+
+static const uint16_t ud_itab__278[] = {
+ /* 0 */ 1182, INVALID, INVALID, 1180,
+};
+
+static const uint16_t ud_itab__279[] = {
+ /* 0 */ 1183, INVALID, INVALID, 1184,
+};
+
+static const uint16_t ud_itab__280[] = {
+ /* 0 */ 1532, INVALID, INVALID, 1530,
+};
+
+static const uint16_t ud_itab__281[] = {
+ /* 0 */ 996, INVALID, INVALID, 994,
+};
+
+static const uint16_t ud_itab__282[] = {
+ /* 0 */ 997, INVALID, INVALID, 998,
+};
+
+static const uint16_t ud_itab__283[] = {
+ /* 0 */ 1000, INVALID, INVALID, 1001,
+};
+
+static const uint16_t ud_itab__284[] = {
+ /* 0 */ 1242, INVALID,
+};
+
+static const uint16_t ud_itab__285[] = {
+ /* 0 */ 1097, INVALID,
+};
+
+static const uint16_t ud_itab__286[] = {
+ /* 0 */ 1243, INVALID,
+};
+
+static const uint16_t ud_itab__287[] = {
+ /* 0 */ 1098, INVALID,
+};
+
+static const uint16_t ud_itab__288[] = {
+ /* 0 */ 173, INVALID,
+};
+
+static const uint16_t ud_itab__289[] = {
+ /* 0 */ 174, INVALID,
+};
+
+static const uint16_t ud_itab__290[] = {
+ /* 0 */ 1, INVALID,
+};
+
+static const uint16_t ud_itab__291[] = {
+ /* 0 */ 4, INVALID,
+};
+
+static const uint16_t ud_itab__292[] = {
+ /* 0 */ GROUP(293), GROUP(294), INVALID,
+};
+
+static const uint16_t ud_itab__293[] = {
+ /* 0 */ 1257, INVALID,
+};
+
+static const uint16_t ud_itab__294[] = {
+ /* 0 */ 1258, INVALID,
+};
+
+static const uint16_t ud_itab__295[] = {
+ /* 0 */ GROUP(296), GROUP(297), INVALID,
+};
+
+static const uint16_t ud_itab__296[] = {
+ /* 0 */ 1110, INVALID,
+};
+
+static const uint16_t ud_itab__297[] = {
+ /* 0 */ 1111, INVALID,
+};
+
+static const uint16_t ud_itab__298[] = {
+ /* 0 */ 1658, INVALID,
+};
+
+static const uint16_t ud_itab__299[] = {
+ /* 0 */ 67, 68,
+};
+
+static const uint16_t ud_itab__300[] = {
+ /* 0 */ 710, 711, INVALID,
+};
+
+static const uint16_t ud_itab__301[] = {
+ /* 0 */ 983, 984, INVALID,
+};
+
+static const uint16_t ud_itab__302[] = {
+ /* 0 */ 21, 970, 11, 1342,
+ /* 4 */ 55, 1413, 1493, 106,
+};
+
+static const uint16_t ud_itab__303[] = {
+ /* 0 */ 23, 971, 13, 1343,
+ /* 4 */ 57, 1414, 1494, 108,
+};
+
+static const uint16_t ud_itab__304[] = {
+ /* 0 */ GROUP(305), GROUP(306), GROUP(307), GROUP(308),
+ /* 4 */ GROUP(309), GROUP(310), GROUP(311), GROUP(312),
+};
+
+static const uint16_t ud_itab__305[] = {
+ /* 0 */ 22, INVALID,
+};
+
+static const uint16_t ud_itab__306[] = {
+ /* 0 */ 972, INVALID,
+};
+
+static const uint16_t ud_itab__307[] = {
+ /* 0 */ 12, INVALID,
+};
+
+static const uint16_t ud_itab__308[] = {
+ /* 0 */ 1344, INVALID,
+};
+
+static const uint16_t ud_itab__309[] = {
+ /* 0 */ 56, INVALID,
+};
+
+static const uint16_t ud_itab__310[] = {
+ /* 0 */ 1415, INVALID,
+};
+
+static const uint16_t ud_itab__311[] = {
+ /* 0 */ 1495, INVALID,
+};
+
+static const uint16_t ud_itab__312[] = {
+ /* 0 */ 107, INVALID,
+};
+
+static const uint16_t ud_itab__313[] = {
+ /* 0 */ 24, 973, 14, 1345,
+ /* 4 */ 58, 1416, 1496, 109,
+};
+
+static const uint16_t ud_itab__314[] = {
+ /* 0 */ 1109, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__315[] = {
+ /* 0 */ 74, 75, 76,
+};
+
+static const uint16_t ud_itab__316[] = {
+ /* 0 */ 170, 171, 172,
+};
+
+static const uint16_t ud_itab__317[] = {
+ /* 0 */ 73, INVALID,
+};
+
+static const uint16_t ud_itab__318[] = {
+ /* 0 */ GROUP(319), GROUP(320), GROUP(321),
+};
+
+static const uint16_t ud_itab__319[] = {
+ /* 0 */ 1259, 1260,
+};
+
+static const uint16_t ud_itab__320[] = {
+ /* 0 */ 1261, 1262,
+};
+
+static const uint16_t ud_itab__321[] = {
+ /* 0 */ INVALID, 1263,
+};
+
+static const uint16_t ud_itab__322[] = {
+ /* 0 */ GROUP(323), GROUP(324), GROUP(325),
+};
+
+static const uint16_t ud_itab__323[] = {
+ /* 0 */ 1112, INVALID,
+};
+
+static const uint16_t ud_itab__324[] = {
+ /* 0 */ 1113, 1114,
+};
+
+static const uint16_t ud_itab__325[] = {
+ /* 0 */ INVALID, 1115,
+};
+
+static const uint16_t ud_itab__326[] = {
+ /* 0 */ 923, 924, 927,
+};
+
+static const uint16_t ud_itab__327[] = {
+ /* 0 */ 115, 116, 119,
+};
+
+static const uint16_t ud_itab__328[] = {
+ /* 0 */ 1403, 1404, 1405,
+};
+
+static const uint16_t ud_itab__329[] = {
+ /* 0 */ 791, 792, 793,
+};
+
+static const uint16_t ud_itab__330[] = {
+ /* 0 */ 1347, 1348, 1349,
+};
+
+static const uint16_t ud_itab__331[] = {
+ /* 0 */ 1279, 1286, 1267, 1275,
+ /* 4 */ 1327, 1334, 1318, 1313,
+};
+
+static const uint16_t ud_itab__332[] = {
+ /* 0 */ 1284, 1287, 1268, 1274,
+ /* 4 */ 1323, 1330, 1319, 1315,
+};
+
+static const uint16_t ud_itab__333[] = {
+ /* 0 */ GROUP(334), GROUP(335), INVALID, INVALID,
+ /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369),
+ /* 8 */ INVALID, GROUP(394), INVALID, INVALID,
+ /* c */ INVALID, GROUP(399), INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__334[] = {
+ /* 0 */ 771, INVALID,
+};
+
+static const uint16_t ud_itab__335[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ 937, 939, GROUP(336), 895,
+ /* 14 */ 1450, 1448, GROUP(337), 885,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ 863, 865, INVALID, 908,
+ /* 2c */ INVALID, INVALID, 1443, 130,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ 901, 1388, 1307, 1292,
+ /* 54 */ 62, 66, 977, 1500,
+ /* 58 */ 28, 947, 146, 135,
+ /* 5c */ 1420, 819, 190, 803,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, GROUP(340),
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, GROUP(338), INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 113, INVALID,
+ /* c4 */ INVALID, INVALID, 1382, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__336[] = {
+ /* 0 */ 893, 897,
+};
+
+static const uint16_t ud_itab__337[] = {
+ /* 0 */ 883, 887,
+};
+
+static const uint16_t ud_itab__338[] = {
+ /* 0 */ GROUP(339), INVALID,
+};
+
+static const uint16_t ud_itab__339[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1401,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__340[] = {
+ /* 0 */ 1742, 1743,
+};
+
+static const uint16_t ud_itab__341[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ 933, 935, GROUP(342), 891,
+ /* 14 */ 1452, 1446, GROUP(343), 881,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ 859, 861, INVALID, 906,
+ /* 2c */ INVALID, INVALID, 1441, 128,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ 899, 1390, INVALID, INVALID,
+ /* 54 */ 60, 64, 975, 1498,
+ /* 58 */ 26, 945, 140, 144,
+ /* 5c */ 1418, 817, 188, 801,
+ /* 60 */ 1208, 1211, 1214, 986,
+ /* 64 */ 1037, 1040, 1043, 992,
+ /* 68 */ 1199, 1202, 1205, 989,
+ /* 6c */ 1548, 1546, GROUP(344), 1518,
+ /* 70 */ 1540, GROUP(345), GROUP(347), GROUP(349),
+ /* 74 */ 1029, 1032, 1035, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ 1550, 1554, GROUP(351), 1516,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 111, INVALID,
+ /* c4 */ 1061, 1054, 1380, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ 34, 1162, 1168, 1174,
+ /* d4 */ 1529, 1095, 919, GROUP(352),
+ /* d8 */ 1194, 1197, 1082, 1016,
+ /* dc */ 1011, 1014, 1077, 1019,
+ /* e0 */ 1022, 1149, 1155, 1025,
+ /* e4 */ 1089, 1091, 161, 903,
+ /* e8 */ 1188, 1191, 1079, 1117,
+ /* ec */ 1005, 1008, 1073, 1265,
+ /* f0 */ INVALID, GROUP(353), GROUP(354), GROUP(355),
+ /* f4 */ INVALID, 1071, 1132, GROUP(356),
+ /* f8 */ 1178, 1181, 1185, 1531,
+ /* fc */ 995, 999, 1002, INVALID,
+};
+
+static const uint16_t ud_itab__342[] = {
+ /* 0 */ 889, INVALID,
+};
+
+static const uint16_t ud_itab__343[] = {
+ /* 0 */ 879, INVALID,
+};
+
+static const uint16_t ud_itab__344[] = {
+ /* 0 */ 869, 871, 912,
+};
+
+static const uint16_t ud_itab__345[] = {
+ /* 0 */ INVALID, INVALID, 1164, INVALID,
+ /* 4 */ 1151, INVALID, GROUP(346), INVALID,
+};
+
+static const uint16_t ud_itab__346[] = {
+ /* 0 */ 1756, INVALID,
+};
+
+static const uint16_t ud_itab__347[] = {
+ /* 0 */ INVALID, INVALID, 1170, INVALID,
+ /* 4 */ 1158, INVALID, GROUP(348), INVALID,
+};
+
+static const uint16_t ud_itab__348[] = {
+ /* 0 */ 1758, INVALID,
+};
+
+static const uint16_t ud_itab__349[] = {
+ /* 0 */ INVALID, INVALID, 1176, 1544,
+ /* 4 */ INVALID, INVALID, GROUP(350), 1542,
+};
+
+static const uint16_t ud_itab__350[] = {
+ /* 0 */ 1760, INVALID,
+};
+
+static const uint16_t ud_itab__351[] = {
+ /* 0 */ 875, 877, 915,
+};
+
+static const uint16_t ud_itab__352[] = {
+ /* 0 */ 1085, INVALID,
+};
+
+static const uint16_t ud_itab__353[] = {
+ /* 0 */ 1755, INVALID,
+};
+
+static const uint16_t ud_itab__354[] = {
+ /* 0 */ 1757, INVALID,
+};
+
+static const uint16_t ud_itab__355[] = {
+ /* 0 */ 1759, INVALID,
+};
+
+static const uint16_t ud_itab__356[] = {
+ /* 0 */ INVALID, 1520,
+};
+
+static const uint16_t ud_itab__357[] = {
+ /* 0 */ 1584, 1587, 1590, 1593,
+ /* 4 */ 1596, 1599, 1602, 1605,
+ /* 8 */ 1608, 1614, 1611, 1617,
+ /* c */ GROUP(358), GROUP(359), GROUP(360), GROUP(361),
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, 1712,
+ /* 18 */ GROUP(362), GROUP(363), INVALID, INVALID,
+ /* 1c */ 1575, 1578, 1581, INVALID,
+ /* 20 */ 1686, 1688, 1690, 1692,
+ /* 24 */ 1694, INVALID, INVALID, INVALID,
+ /* 28 */ 1623, 1709, 1682, 1684,
+ /* 2c */ GROUP(365), GROUP(366), GROUP(367), GROUP(368),
+ /* 30 */ 1697, 1699, 1701, 1703,
+ /* 34 */ 1705, 1707, INVALID, 1718,
+ /* 38 */ 1625, 1627, 1629, 1631,
+ /* 3c */ 1633, 1635, 1639, 1637,
+ /* 40 */ 1641, 1643, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, 46,
+ /* dc */ 42, 44, 38, 40,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__358[] = {
+ /* 0 */ 1737, INVALID,
+};
+
+static const uint16_t ud_itab__359[] = {
+ /* 0 */ 1735, INVALID,
+};
+
+static const uint16_t ud_itab__360[] = {
+ /* 0 */ 1740, INVALID,
+};
+
+static const uint16_t ud_itab__361[] = {
+ /* 0 */ 1741, INVALID,
+};
+
+static const uint16_t ud_itab__362[] = {
+ /* 0 */ 1727, INVALID,
+};
+
+static const uint16_t ud_itab__363[] = {
+ /* 0 */ GROUP(364), INVALID,
+};
+
+static const uint16_t ud_itab__364[] = {
+ /* 0 */ INVALID, 1728,
+};
+
+static const uint16_t ud_itab__365[] = {
+ /* 0 */ 1731, INVALID,
+};
+
+static const uint16_t ud_itab__366[] = {
+ /* 0 */ 1733, INVALID,
+};
+
+static const uint16_t ud_itab__367[] = {
+ /* 0 */ 1732, INVALID,
+};
+
+static const uint16_t ud_itab__368[] = {
+ /* 0 */ 1734, INVALID,
+};
+
+static const uint16_t ud_itab__369[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ GROUP(370), GROUP(371), GROUP(372), INVALID,
+ /* 8 */ 1645, 1647, 1649, 1651,
+ /* c */ 1655, 1653, 1678, 1620,
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ GROUP(374), 1057, GROUP(375), 202,
+ /* 18 */ GROUP(379), GROUP(381), INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ GROUP(383), 1558, GROUP(385), INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ 198, 196, 1680, INVALID,
+ /* 44 */ 1513, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, GROUP(391), GROUP(392),
+ /* 4c */ GROUP(393), INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ 1716, 1714, 1722, 1720,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, 48,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__370[] = {
+ /* 0 */ 1738, INVALID,
+};
+
+static const uint16_t ud_itab__371[] = {
+ /* 0 */ 1736, INVALID,
+};
+
+static const uint16_t ud_itab__372[] = {
+ /* 0 */ GROUP(373), INVALID,
+};
+
+static const uint16_t ud_itab__373[] = {
+ /* 0 */ INVALID, 1739,
+};
+
+static const uint16_t ud_itab__374[] = {
+ /* 0 */ 1046, INVALID,
+};
+
+static const uint16_t ud_itab__375[] = {
+ /* 0 */ GROUP(376), GROUP(377), GROUP(378),
+};
+
+static const uint16_t ud_itab__376[] = {
+ /* 0 */ 1048, INVALID,
+};
+
+static const uint16_t ud_itab__377[] = {
+ /* 0 */ 1050, INVALID,
+};
+
+static const uint16_t ud_itab__378[] = {
+ /* 0 */ INVALID, 1052,
+};
+
+static const uint16_t ud_itab__379[] = {
+ /* 0 */ GROUP(380), INVALID,
+};
+
+static const uint16_t ud_itab__380[] = {
+ /* 0 */ INVALID, 1730,
+};
+
+static const uint16_t ud_itab__381[] = {
+ /* 0 */ GROUP(382), INVALID,
+};
+
+static const uint16_t ud_itab__382[] = {
+ /* 0 */ INVALID, 1729,
+};
+
+static const uint16_t ud_itab__383[] = {
+ /* 0 */ GROUP(384), INVALID,
+};
+
+static const uint16_t ud_itab__384[] = {
+ /* 0 */ 1065, INVALID,
+};
+
+static const uint16_t ud_itab__385[] = {
+ /* 0 */ GROUP(386), GROUP(388),
+};
+
+static const uint16_t ud_itab__386[] = {
+ /* 0 */ GROUP(387), INVALID,
+};
+
+static const uint16_t ud_itab__387[] = {
+ /* 0 */ 1066, INVALID,
+};
+
+static const uint16_t ud_itab__388[] = {
+ /* 0 */ GROUP(389), GROUP(390),
+};
+
+static const uint16_t ud_itab__389[] = {
+ /* 0 */ 1067, INVALID,
+};
+
+static const uint16_t ud_itab__390[] = {
+ /* 0 */ 1068, INVALID,
+};
+
+static const uint16_t ud_itab__391[] = {
+ /* 0 */ 1745, INVALID,
+};
+
+static const uint16_t ud_itab__392[] = {
+ /* 0 */ 1744, INVALID,
+};
+
+static const uint16_t ud_itab__393[] = {
+ /* 0 */ 1754, INVALID,
+};
+
+static const uint16_t ud_itab__394[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ GROUP(395), GROUP(396), GROUP(397), INVALID,
+ /* 14 */ INVALID, INVALID, GROUP(398), INVALID,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, 155, INVALID,
+ /* 2c */ 169, 159, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, 1394, 1309, 1294,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ 32, 951, 157, 164,
+ /* 5c */ 1424, 823, 194, 807,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, 1523,
+ /* 70 */ 1536, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, 917, 1525,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 121, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, 133, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__395[] = {
+ /* 0 */ 1751, 1750,
+};
+
+static const uint16_t ud_itab__396[] = {
+ /* 0 */ 1753, 1752,
+};
+
+static const uint16_t ud_itab__397[] = {
+ /* 0 */ 1572, 1570,
+};
+
+static const uint16_t ud_itab__398[] = {
+ /* 0 */ 1568, 1566,
+};
+
+static const uint16_t ud_itab__399[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ GROUP(402), GROUP(400), GROUP(401), INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, INVALID,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, 153, INVALID,
+ /* 2c */ 167, 149, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, 1392, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ 30, 949, 151, INVALID,
+ /* 5c */ 1422, 821, 192, 805,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ 1538, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ 1552, 1556, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 118, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ 36, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, 137, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ 1560, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__400[] = {
+ /* 0 */ 1749, 1748,
+};
+
+static const uint16_t ud_itab__401[] = {
+ /* 0 */ 1564, 1562,
+};
+
+static const uint16_t ud_itab__402[] = {
+ /* 0 */ 1747, 1746,
+};
+
+static const uint16_t ud_itab__403[] = {
+ /* 0 */ GROUP(404), GROUP(335), INVALID, INVALID,
+ /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369),
+ /* 8 */ INVALID, GROUP(394), INVALID, INVALID,
+ /* c */ INVALID, GROUP(399), INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__404[] = {
+ /* 0 */ 769, INVALID,
+};
+
+static const uint16_t ud_itab__405[] = {
+ /* 0 */ 826, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__406[] = {
+ /* 0 */ 827, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__407[] = {
+ /* 0 */ 715, INVALID,
+};
+
+static const uint16_t ud_itab__408[] = {
+ /* 0 */ 723, 724, 725,
+};
+
+static const uint16_t ud_itab__409[] = {
+ /* 0 */ 1280, 1285, 1269, 1273,
+ /* 4 */ 1326, 1333, 1320, 1314,
+};
+
+static const uint16_t ud_itab__410[] = {
+ /* 0 */ 1281, 1288, 1272, 1276,
+ /* 4 */ 1325, 1332, 1329, 1312,
+};
+
+static const uint16_t ud_itab__411[] = {
+ /* 0 */ 1282, 1289, 1270, 1277,
+ /* 4 */ 1324, 1331, 1321, 1316,
+};
+
+static const uint16_t ud_itab__412[] = {
+ /* 0 */ 1283, 1290, 1271, 1278,
+ /* 4 */ 1328, 1335, 1322, 1317,
+};
+
+static const uint16_t ud_itab__413[] = {
+ /* 0 */ 3, INVALID,
+};
+
+static const uint16_t ud_itab__414[] = {
+ /* 0 */ 2, INVALID,
+};
+
+static const uint16_t ud_itab__415[] = {
+ /* 0 */ 1311, INVALID,
+};
+
+static const uint16_t ud_itab__416[] = {
+ /* 0 */ GROUP(417), GROUP(418),
+};
+
+static const uint16_t ud_itab__417[] = {
+ /* 0 */ 206, 503, 307, 357,
+ /* 4 */ 587, 630, 387, 413,
+};
+
+static const uint16_t ud_itab__418[] = {
+ /* 0 */ 215, 216, 217, 218,
+ /* 4 */ 219, 220, 221, 222,
+ /* 8 */ 504, 505, 506, 507,
+ /* c */ 508, 509, 510, 511,
+ /* 10 */ 309, 310, 311, 312,
+ /* 14 */ 313, 314, 315, 316,
+ /* 18 */ 359, 360, 361, 362,
+ /* 1c */ 363, 364, 365, 366,
+ /* 20 */ 589, 590, 591, 592,
+ /* 24 */ 593, 594, 595, 596,
+ /* 28 */ 614, 615, 616, 617,
+ /* 2c */ 618, 619, 620, 621,
+ /* 30 */ 388, 389, 390, 391,
+ /* 34 */ 392, 393, 394, 395,
+ /* 38 */ 414, 415, 416, 417,
+ /* 3c */ 418, 419, 420, 421,
+};
+
+static const uint16_t ud_itab__419[] = {
+ /* 0 */ GROUP(420), GROUP(421),
+};
+
+static const uint16_t ud_itab__420[] = {
+ /* 0 */ 476, INVALID, 573, 540,
+ /* 4 */ 493, 492, 584, 583,
+};
+
+static const uint16_t ud_itab__421[] = {
+ /* 0 */ 477, 478, 479, 480,
+ /* 4 */ 481, 482, 483, 484,
+ /* 8 */ 658, 659, 660, 661,
+ /* c */ 662, 663, 664, 665,
+ /* 10 */ 522, INVALID, INVALID, INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, INVALID,
+ /* 18 */ 549, 550, 551, 552,
+ /* 1c */ 553, 554, 555, 556,
+ /* 20 */ 233, 204, INVALID, INVALID,
+ /* 24 */ 639, 657, INVALID, INVALID,
+ /* 28 */ 485, 486, 487, 488,
+ /* 2c */ 489, 490, 491, INVALID,
+ /* 30 */ 203, 685, 529, 526,
+ /* 34 */ 684, 528, 377, 454,
+ /* 38 */ 527, 686, 537, 536,
+ /* 3c */ 530, 534, 535, 376,
+};
+
+static const uint16_t ud_itab__422[] = {
+ /* 0 */ GROUP(423), GROUP(424),
+};
+
+static const uint16_t ud_itab__423[] = {
+ /* 0 */ 456, 520, 448, 450,
+ /* 4 */ 462, 464, 460, 458,
+};
+
+static const uint16_t ud_itab__424[] = {
+ /* 0 */ 235, 236, 237, 238,
+ /* 4 */ 239, 240, 241, 242,
+ /* 8 */ 243, 244, 245, 246,
+ /* c */ 247, 248, 249, 250,
+ /* 10 */ 251, 252, 253, 254,
+ /* 14 */ 255, 256, 257, 258,
+ /* 18 */ 259, 260, 261, 262,
+ /* 1c */ 263, 264, 265, 266,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, 656, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__425[] = {
+ /* 0 */ GROUP(426), GROUP(427),
+};
+
+static const uint16_t ud_itab__426[] = {
+ /* 0 */ 453, 471, 467, 470,
+ /* 4 */ INVALID, 474, INVALID, 538,
+};
+
+static const uint16_t ud_itab__427[] = {
+ /* 0 */ 267, 268, 269, 270,
+ /* 4 */ 271, 272, 273, 274,
+ /* 8 */ 275, 276, 277, 278,
+ /* c */ 279, 280, 281, 282,
+ /* 10 */ 283, 284, 285, 286,
+ /* 14 */ 287, 288, 289, 290,
+ /* 18 */ 291, 292, 293, 294,
+ /* 1c */ 295, 296, 297, 298,
+ /* 20 */ 524, 523, 234, 455,
+ /* 24 */ 525, 532, INVALID, INVALID,
+ /* 28 */ 299, 300, 301, 302,
+ /* 2c */ 303, 304, 305, 306,
+ /* 30 */ 333, 334, 335, 336,
+ /* 34 */ 337, 338, 339, 340,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__428[] = {
+ /* 0 */ GROUP(429), GROUP(430),
+};
+
+static const uint16_t ud_itab__429[] = {
+ /* 0 */ 205, 494, 308, 358,
+ /* 4 */ 588, 613, 378, 404,
+};
+
+static const uint16_t ud_itab__430[] = {
+ /* 0 */ 207, 208, 209, 210,
+ /* 4 */ 211, 212, 213, 214,
+ /* 8 */ 495, 496, 497, 498,
+ /* c */ 499, 500, 501, 502,
+ /* 10 */ 317, 318, 319, 320,
+ /* 14 */ 321, 322, 323, 324,
+ /* 18 */ 325, 326, 327, 328,
+ /* 1c */ 329, 330, 331, 332,
+ /* 20 */ 622, 623, 624, 625,
+ /* 24 */ 626, 627, 628, 629,
+ /* 28 */ 597, 598, 599, 600,
+ /* 2c */ 601, 602, 603, 604,
+ /* 30 */ 405, 406, 407, 408,
+ /* 34 */ 409, 410, 411, 412,
+ /* 38 */ 379, 380, 381, 382,
+ /* 3c */ 383, 384, 385, 386,
+};
+
+static const uint16_t ud_itab__431[] = {
+ /* 0 */ GROUP(432), GROUP(433),
+};
+
+static const uint16_t ud_itab__432[] = {
+ /* 0 */ 475, 472, 574, 539,
+ /* 4 */ 531, INVALID, 533, 585,
+};
+
+static const uint16_t ud_itab__433[] = {
+ /* 0 */ 431, 432, 433, 434,
+ /* 4 */ 435, 436, 437, 438,
+ /* 8 */ 666, 667, 668, 669,
+ /* c */ 670, 671, 672, 673,
+ /* 10 */ 575, 576, 577, 578,
+ /* 14 */ 579, 580, 581, 582,
+ /* 18 */ 541, 542, 543, 544,
+ /* 1c */ 545, 546, 547, 548,
+ /* 20 */ 640, 641, 642, 643,
+ /* 24 */ 644, 645, 646, 647,
+ /* 28 */ 648, 649, 650, 651,
+ /* 2c */ 652, 653, 654, 655,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__434[] = {
+ /* 0 */ GROUP(435), GROUP(436),
+};
+
+static const uint16_t ud_itab__435[] = {
+ /* 0 */ 457, 521, 447, 449,
+ /* 4 */ 463, 465, 461, 459,
+};
+
+static const uint16_t ud_itab__436[] = {
+ /* 0 */ 223, 224, 225, 226,
+ /* 4 */ 227, 228, 229, 230,
+ /* 8 */ 512, 513, 514, 515,
+ /* c */ 516, 517, 518, 519,
+ /* 10 */ 367, 368, 369, 370,
+ /* 14 */ 371, 372, 373, 374,
+ /* 18 */ INVALID, 375, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ 631, 632, 633, 634,
+ /* 24 */ 635, 636, 637, 638,
+ /* 28 */ 605, 606, 607, 608,
+ /* 2c */ 609, 610, 611, 612,
+ /* 30 */ 422, 423, 424, 425,
+ /* 34 */ 426, 427, 428, 429,
+ /* 38 */ 396, 397, 398, 399,
+ /* 3c */ 400, 401, 402, 403,
+};
+
+static const uint16_t ud_itab__437[] = {
+ /* 0 */ GROUP(438), GROUP(439),
+};
+
+static const uint16_t ud_itab__438[] = {
+ /* 0 */ 451, 473, 466, 468,
+ /* 4 */ 231, 452, 232, 469,
+};
+
+static const uint16_t ud_itab__439[] = {
+ /* 0 */ 439, 440, 441, 442,
+ /* 4 */ 443, 444, 445, 446,
+ /* 8 */ 674, 675, 676, 677,
+ /* c */ 678, 679, 680, 681,
+ /* 10 */ 557, 558, 559, 560,
+ /* 14 */ 561, 562, 563, 564,
+ /* 18 */ 565, 566, 567, 568,
+ /* 1c */ 569, 570, 571, 572,
+ /* 20 */ 586, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ 341, 342, 343, 344,
+ /* 2c */ 345, 346, 347, 348,
+ /* 30 */ 349, 350, 351, 352,
+ /* 34 */ 353, 354, 355, 356,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__440[] = {
+ /* 0 */ 758, 759, 760,
+};
+
+static const uint16_t ud_itab__441[] = {
+ /* 0 */ 764, INVALID,
+};
+
+static const uint16_t ud_itab__442[] = {
+ /* 0 */ 1432, 1437, 962, 953,
+ /* 4 */ 942, 695, 186, 689,
+};
+
+static const uint16_t ud_itab__443[] = {
+ /* 0 */ 1438, 1439, 963, 954,
+ /* 4 */ 943, 696, 185, 688,
+};
+
+static const uint16_t ud_itab__444[] = {
+ /* 0 */ 708, 183, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__445[] = {
+ /* 0 */ 707, 184, GROUP(446), 71,
+ /* 4 */ 761, 762, 1255, INVALID,
+};
+
+static const uint16_t ud_itab__446[] = {
+ /* 0 */ 69, 70,
+};
+
+
+struct ud_lookup_table_list_entry ud_lookup_table_list[] = {
+ /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" },
+ /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" },
+ /* 003 */ { ud_itab__3, UD_TAB__OPC_MODE, "/m" },
+ /* 004 */ { ud_itab__4, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 005 */ { ud_itab__5, UD_TAB__OPC_REG, "/reg" },
+ /* 006 */ { ud_itab__6, UD_TAB__OPC_MOD, "/mod" },
+ /* 007 */ { ud_itab__7, UD_TAB__OPC_REG, "/reg" },
+ /* 008 */ { ud_itab__8, UD_TAB__OPC_REG, "/reg" },
+ /* 009 */ { ud_itab__9, UD_TAB__OPC_RM, "/rm" },
+ /* 010 */ { ud_itab__10, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 011 */ { ud_itab__11, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 012 */ { ud_itab__12, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 013 */ { ud_itab__13, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 014 */ { ud_itab__14, UD_TAB__OPC_RM, "/rm" },
+ /* 015 */ { ud_itab__15, UD_TAB__OPC_RM, "/rm" },
+ /* 016 */ { ud_itab__16, UD_TAB__OPC_RM, "/rm" },
+ /* 017 */ { ud_itab__17, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 018 */ { ud_itab__18, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 019 */ { ud_itab__19, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 020 */ { ud_itab__20, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 021 */ { ud_itab__21, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 022 */ { ud_itab__22, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 023 */ { ud_itab__23, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 024 */ { ud_itab__24, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 025 */ { ud_itab__25, UD_TAB__OPC_RM, "/rm" },
+ /* 026 */ { ud_itab__26, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 027 */ { ud_itab__27, UD_TAB__OPC_REG, "/reg" },
+ /* 028 */ { ud_itab__28, UD_TAB__OPC_3DNOW, "/3dnow" },
+ /* 029 */ { ud_itab__29, UD_TAB__OPC_SSE, "/sse" },
+ /* 030 */ { ud_itab__30, UD_TAB__OPC_SSE, "/sse" },
+ /* 031 */ { ud_itab__31, UD_TAB__OPC_MOD, "/mod" },
+ /* 032 */ { ud_itab__32, UD_TAB__OPC_SSE, "/sse" },
+ /* 033 */ { ud_itab__33, UD_TAB__OPC_SSE, "/sse" },
+ /* 034 */ { ud_itab__34, UD_TAB__OPC_SSE, "/sse" },
+ /* 035 */ { ud_itab__35, UD_TAB__OPC_SSE, "/sse" },
+ /* 036 */ { ud_itab__36, UD_TAB__OPC_SSE, "/sse" },
+ /* 037 */ { ud_itab__37, UD_TAB__OPC_MOD, "/mod" },
+ /* 038 */ { ud_itab__38, UD_TAB__OPC_SSE, "/sse" },
+ /* 039 */ { ud_itab__39, UD_TAB__OPC_SSE, "/sse" },
+ /* 040 */ { ud_itab__40, UD_TAB__OPC_SSE, "/sse" },
+ /* 041 */ { ud_itab__41, UD_TAB__OPC_REG, "/reg" },
+ /* 042 */ { ud_itab__42, UD_TAB__OPC_SSE, "/sse" },
+ /* 043 */ { ud_itab__43, UD_TAB__OPC_SSE, "/sse" },
+ /* 044 */ { ud_itab__44, UD_TAB__OPC_SSE, "/sse" },
+ /* 045 */ { ud_itab__45, UD_TAB__OPC_SSE, "/sse" },
+ /* 046 */ { ud_itab__46, UD_TAB__OPC_SSE, "/sse" },
+ /* 047 */ { ud_itab__47, UD_TAB__OPC_SSE, "/sse" },
+ /* 048 */ { ud_itab__48, UD_TAB__OPC_SSE, "/sse" },
+ /* 049 */ { ud_itab__49, UD_TAB__OPC_SSE, "/sse" },
+ /* 050 */ { ud_itab__50, UD_TAB__OPC_MODE, "/m" },
+ /* 051 */ { ud_itab__51, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 052 */ { ud_itab__52, UD_TAB__OPC_MODE, "/m" },
+ /* 053 */ { ud_itab__53, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 054 */ { ud_itab__54, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 055 */ { ud_itab__55, UD_TAB__OPC_SSE, "/sse" },
+ /* 056 */ { ud_itab__56, UD_TAB__OPC_MODE, "/m" },
+ /* 057 */ { ud_itab__57, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 058 */ { ud_itab__58, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 059 */ { ud_itab__59, UD_TAB__OPC_SSE, "/sse" },
+ /* 060 */ { ud_itab__60, UD_TAB__OPC_MODE, "/m" },
+ /* 061 */ { ud_itab__61, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 062 */ { ud_itab__62, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 063 */ { ud_itab__63, UD_TAB__OPC_SSE, "/sse" },
+ /* 064 */ { ud_itab__64, UD_TAB__OPC_SSE, "/sse" },
+ /* 065 */ { ud_itab__65, UD_TAB__OPC_SSE, "/sse" },
+ /* 066 */ { ud_itab__66, UD_TAB__OPC_SSE, "/sse" },
+ /* 067 */ { ud_itab__67, UD_TAB__OPC_SSE, "/sse" },
+ /* 068 */ { ud_itab__68, UD_TAB__OPC_SSE, "/sse" },
+ /* 069 */ { ud_itab__69, UD_TAB__OPC_SSE, "/sse" },
+ /* 070 */ { ud_itab__70, UD_TAB__OPC_SSE, "/sse" },
+ /* 071 */ { ud_itab__71, UD_TAB__OPC_SSE, "/sse" },
+ /* 072 */ { ud_itab__72, UD_TAB__OPC_SSE, "/sse" },
+ /* 073 */ { ud_itab__73, UD_TAB__OPC_SSE, "/sse" },
+ /* 074 */ { ud_itab__74, UD_TAB__OPC_SSE, "/sse" },
+ /* 075 */ { ud_itab__75, UD_TAB__OPC_SSE, "/sse" },
+ /* 076 */ { ud_itab__76, UD_TAB__OPC_SSE, "/sse" },
+ /* 077 */ { ud_itab__77, UD_TAB__OPC_SSE, "/sse" },
+ /* 078 */ { ud_itab__78, UD_TAB__OPC_SSE, "/sse" },
+ /* 079 */ { ud_itab__79, UD_TAB__OPC_SSE, "/sse" },
+ /* 080 */ { ud_itab__80, UD_TAB__OPC_SSE, "/sse" },
+ /* 081 */ { ud_itab__81, UD_TAB__OPC_SSE, "/sse" },
+ /* 082 */ { ud_itab__82, UD_TAB__OPC_SSE, "/sse" },
+ /* 083 */ { ud_itab__83, UD_TAB__OPC_SSE, "/sse" },
+ /* 084 */ { ud_itab__84, UD_TAB__OPC_SSE, "/sse" },
+ /* 085 */ { ud_itab__85, UD_TAB__OPC_SSE, "/sse" },
+ /* 086 */ { ud_itab__86, UD_TAB__OPC_SSE, "/sse" },
+ /* 087 */ { ud_itab__87, UD_TAB__OPC_SSE, "/sse" },
+ /* 088 */ { ud_itab__88, UD_TAB__OPC_SSE, "/sse" },
+ /* 089 */ { ud_itab__89, UD_TAB__OPC_SSE, "/sse" },
+ /* 090 */ { ud_itab__90, UD_TAB__OPC_SSE, "/sse" },
+ /* 091 */ { ud_itab__91, UD_TAB__OPC_SSE, "/sse" },
+ /* 092 */ { ud_itab__92, UD_TAB__OPC_SSE, "/sse" },
+ /* 093 */ { ud_itab__93, UD_TAB__OPC_SSE, "/sse" },
+ /* 094 */ { ud_itab__94, UD_TAB__OPC_SSE, "/sse" },
+ /* 095 */ { ud_itab__95, UD_TAB__OPC_SSE, "/sse" },
+ /* 096 */ { ud_itab__96, UD_TAB__OPC_SSE, "/sse" },
+ /* 097 */ { ud_itab__97, UD_TAB__OPC_SSE, "/sse" },
+ /* 098 */ { ud_itab__98, UD_TAB__OPC_SSE, "/sse" },
+ /* 099 */ { ud_itab__99, UD_TAB__OPC_SSE, "/sse" },
+ /* 100 */ { ud_itab__100, UD_TAB__OPC_SSE, "/sse" },
+ /* 101 */ { ud_itab__101, UD_TAB__OPC_SSE, "/sse" },
+ /* 102 */ { ud_itab__102, UD_TAB__OPC_SSE, "/sse" },
+ /* 103 */ { ud_itab__103, UD_TAB__OPC_SSE, "/sse" },
+ /* 104 */ { ud_itab__104, UD_TAB__OPC_SSE, "/sse" },
+ /* 105 */ { ud_itab__105, UD_TAB__OPC_SSE, "/sse" },
+ /* 106 */ { ud_itab__106, UD_TAB__OPC_SSE, "/sse" },
+ /* 107 */ { ud_itab__107, UD_TAB__OPC_SSE, "/sse" },
+ /* 108 */ { ud_itab__108, UD_TAB__OPC_SSE, "/sse" },
+ /* 109 */ { ud_itab__109, UD_TAB__OPC_SSE, "/sse" },
+ /* 110 */ { ud_itab__110, UD_TAB__OPC_SSE, "/sse" },
+ /* 111 */ { ud_itab__111, UD_TAB__OPC_SSE, "/sse" },
+ /* 112 */ { ud_itab__112, UD_TAB__OPC_SSE, "/sse" },
+ /* 113 */ { ud_itab__113, UD_TAB__OPC_SSE, "/sse" },
+ /* 114 */ { ud_itab__114, UD_TAB__OPC_SSE, "/sse" },
+ /* 115 */ { ud_itab__115, UD_TAB__OPC_SSE, "/sse" },
+ /* 116 */ { ud_itab__116, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 117 */ { ud_itab__117, UD_TAB__OPC_SSE, "/sse" },
+ /* 118 */ { ud_itab__118, UD_TAB__OPC_SSE, "/sse" },
+ /* 119 */ { ud_itab__119, UD_TAB__OPC_SSE, "/sse" },
+ /* 120 */ { ud_itab__120, UD_TAB__OPC_SSE, "/sse" },
+ /* 121 */ { ud_itab__121, UD_TAB__OPC_SSE, "/sse" },
+ /* 122 */ { ud_itab__122, UD_TAB__OPC_SSE, "/sse" },
+ /* 123 */ { ud_itab__123, UD_TAB__OPC_SSE, "/sse" },
+ /* 124 */ { ud_itab__124, UD_TAB__OPC_SSE, "/sse" },
+ /* 125 */ { ud_itab__125, UD_TAB__OPC_SSE, "/sse" },
+ /* 126 */ { ud_itab__126, UD_TAB__OPC_SSE, "/sse" },
+ /* 127 */ { ud_itab__127, UD_TAB__OPC_SSE, "/sse" },
+ /* 128 */ { ud_itab__128, UD_TAB__OPC_OSIZE, "/o" },
+ /* 129 */ { ud_itab__129, UD_TAB__OPC_SSE, "/sse" },
+ /* 130 */ { ud_itab__130, UD_TAB__OPC_SSE, "/sse" },
+ /* 131 */ { ud_itab__131, UD_TAB__OPC_SSE, "/sse" },
+ /* 132 */ { ud_itab__132, UD_TAB__OPC_SSE, "/sse" },
+ /* 133 */ { ud_itab__133, UD_TAB__OPC_OSIZE, "/o" },
+ /* 134 */ { ud_itab__134, UD_TAB__OPC_SSE, "/sse" },
+ /* 135 */ { ud_itab__135, UD_TAB__OPC_SSE, "/sse" },
+ /* 136 */ { ud_itab__136, UD_TAB__OPC_SSE, "/sse" },
+ /* 137 */ { ud_itab__137, UD_TAB__OPC_SSE, "/sse" },
+ /* 138 */ { ud_itab__138, UD_TAB__OPC_SSE, "/sse" },
+ /* 139 */ { ud_itab__139, UD_TAB__OPC_SSE, "/sse" },
+ /* 140 */ { ud_itab__140, UD_TAB__OPC_SSE, "/sse" },
+ /* 141 */ { ud_itab__141, UD_TAB__OPC_SSE, "/sse" },
+ /* 142 */ { ud_itab__142, UD_TAB__OPC_SSE, "/sse" },
+ /* 143 */ { ud_itab__143, UD_TAB__OPC_SSE, "/sse" },
+ /* 144 */ { ud_itab__144, UD_TAB__OPC_SSE, "/sse" },
+ /* 145 */ { ud_itab__145, UD_TAB__OPC_SSE, "/sse" },
+ /* 146 */ { ud_itab__146, UD_TAB__OPC_SSE, "/sse" },
+ /* 147 */ { ud_itab__147, UD_TAB__OPC_SSE, "/sse" },
+ /* 148 */ { ud_itab__148, UD_TAB__OPC_SSE, "/sse" },
+ /* 149 */ { ud_itab__149, UD_TAB__OPC_SSE, "/sse" },
+ /* 150 */ { ud_itab__150, UD_TAB__OPC_SSE, "/sse" },
+ /* 151 */ { ud_itab__151, UD_TAB__OPC_SSE, "/sse" },
+ /* 152 */ { ud_itab__152, UD_TAB__OPC_SSE, "/sse" },
+ /* 153 */ { ud_itab__153, UD_TAB__OPC_SSE, "/sse" },
+ /* 154 */ { ud_itab__154, UD_TAB__OPC_SSE, "/sse" },
+ /* 155 */ { ud_itab__155, UD_TAB__OPC_SSE, "/sse" },
+ /* 156 */ { ud_itab__156, UD_TAB__OPC_SSE, "/sse" },
+ /* 157 */ { ud_itab__157, UD_TAB__OPC_SSE, "/sse" },
+ /* 158 */ { ud_itab__158, UD_TAB__OPC_SSE, "/sse" },
+ /* 159 */ { ud_itab__159, UD_TAB__OPC_SSE, "/sse" },
+ /* 160 */ { ud_itab__160, UD_TAB__OPC_SSE, "/sse" },
+ /* 161 */ { ud_itab__161, UD_TAB__OPC_SSE, "/sse" },
+ /* 162 */ { ud_itab__162, UD_TAB__OPC_SSE, "/sse" },
+ /* 163 */ { ud_itab__163, UD_TAB__OPC_SSE, "/sse" },
+ /* 164 */ { ud_itab__164, UD_TAB__OPC_SSE, "/sse" },
+ /* 165 */ { ud_itab__165, UD_TAB__OPC_SSE, "/sse" },
+ /* 166 */ { ud_itab__166, UD_TAB__OPC_SSE, "/sse" },
+ /* 167 */ { ud_itab__167, UD_TAB__OPC_SSE, "/sse" },
+ /* 168 */ { ud_itab__168, UD_TAB__OPC_SSE, "/sse" },
+ /* 169 */ { ud_itab__169, UD_TAB__OPC_SSE, "/sse" },
+ /* 170 */ { ud_itab__170, UD_TAB__OPC_SSE, "/sse" },
+ /* 171 */ { ud_itab__171, UD_TAB__OPC_SSE, "/sse" },
+ /* 172 */ { ud_itab__172, UD_TAB__OPC_SSE, "/sse" },
+ /* 173 */ { ud_itab__173, UD_TAB__OPC_SSE, "/sse" },
+ /* 174 */ { ud_itab__174, UD_TAB__OPC_OSIZE, "/o" },
+ /* 175 */ { ud_itab__175, UD_TAB__OPC_OSIZE, "/o" },
+ /* 176 */ { ud_itab__176, UD_TAB__OPC_SSE, "/sse" },
+ /* 177 */ { ud_itab__177, UD_TAB__OPC_SSE, "/sse" },
+ /* 178 */ { ud_itab__178, UD_TAB__OPC_REG, "/reg" },
+ /* 179 */ { ud_itab__179, UD_TAB__OPC_SSE, "/sse" },
+ /* 180 */ { ud_itab__180, UD_TAB__OPC_SSE, "/sse" },
+ /* 181 */ { ud_itab__181, UD_TAB__OPC_SSE, "/sse" },
+ /* 182 */ { ud_itab__182, UD_TAB__OPC_REG, "/reg" },
+ /* 183 */ { ud_itab__183, UD_TAB__OPC_SSE, "/sse" },
+ /* 184 */ { ud_itab__184, UD_TAB__OPC_SSE, "/sse" },
+ /* 185 */ { ud_itab__185, UD_TAB__OPC_SSE, "/sse" },
+ /* 186 */ { ud_itab__186, UD_TAB__OPC_REG, "/reg" },
+ /* 187 */ { ud_itab__187, UD_TAB__OPC_SSE, "/sse" },
+ /* 188 */ { ud_itab__188, UD_TAB__OPC_SSE, "/sse" },
+ /* 189 */ { ud_itab__189, UD_TAB__OPC_SSE, "/sse" },
+ /* 190 */ { ud_itab__190, UD_TAB__OPC_SSE, "/sse" },
+ /* 191 */ { ud_itab__191, UD_TAB__OPC_SSE, "/sse" },
+ /* 192 */ { ud_itab__192, UD_TAB__OPC_SSE, "/sse" },
+ /* 193 */ { ud_itab__193, UD_TAB__OPC_SSE, "/sse" },
+ /* 194 */ { ud_itab__194, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 195 */ { ud_itab__195, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 196 */ { ud_itab__196, UD_TAB__OPC_SSE, "/sse" },
+ /* 197 */ { ud_itab__197, UD_TAB__OPC_SSE, "/sse" },
+ /* 198 */ { ud_itab__198, UD_TAB__OPC_SSE, "/sse" },
+ /* 199 */ { ud_itab__199, UD_TAB__OPC_OSIZE, "/o" },
+ /* 200 */ { ud_itab__200, UD_TAB__OPC_OSIZE, "/o" },
+ /* 201 */ { ud_itab__201, UD_TAB__OPC_SSE, "/sse" },
+ /* 202 */ { ud_itab__202, UD_TAB__OPC_MOD, "/mod" },
+ /* 203 */ { ud_itab__203, UD_TAB__OPC_REG, "/reg" },
+ /* 204 */ { ud_itab__204, UD_TAB__OPC_RM, "/rm" },
+ /* 205 */ { ud_itab__205, UD_TAB__OPC_RM, "/rm" },
+ /* 206 */ { ud_itab__206, UD_TAB__OPC_RM, "/rm" },
+ /* 207 */ { ud_itab__207, UD_TAB__OPC_MOD, "/mod" },
+ /* 208 */ { ud_itab__208, UD_TAB__OPC_REG, "/reg" },
+ /* 209 */ { ud_itab__209, UD_TAB__OPC_RM, "/rm" },
+ /* 210 */ { ud_itab__210, UD_TAB__OPC_RM, "/rm" },
+ /* 211 */ { ud_itab__211, UD_TAB__OPC_RM, "/rm" },
+ /* 212 */ { ud_itab__212, UD_TAB__OPC_RM, "/rm" },
+ /* 213 */ { ud_itab__213, UD_TAB__OPC_RM, "/rm" },
+ /* 214 */ { ud_itab__214, UD_TAB__OPC_RM, "/rm" },
+ /* 215 */ { ud_itab__215, UD_TAB__OPC_MOD, "/mod" },
+ /* 216 */ { ud_itab__216, UD_TAB__OPC_REG, "/reg" },
+ /* 217 */ { ud_itab__217, UD_TAB__OPC_REG, "/reg" },
+ /* 218 */ { ud_itab__218, UD_TAB__OPC_RM, "/rm" },
+ /* 219 */ { ud_itab__219, UD_TAB__OPC_RM, "/rm" },
+ /* 220 */ { ud_itab__220, UD_TAB__OPC_RM, "/rm" },
+ /* 221 */ { ud_itab__221, UD_TAB__OPC_SSE, "/sse" },
+ /* 222 */ { ud_itab__222, UD_TAB__OPC_REG, "/reg" },
+ /* 223 */ { ud_itab__223, UD_TAB__OPC_SSE, "/sse" },
+ /* 224 */ { ud_itab__224, UD_TAB__OPC_SSE, "/sse" },
+ /* 225 */ { ud_itab__225, UD_TAB__OPC_SSE, "/sse" },
+ /* 226 */ { ud_itab__226, UD_TAB__OPC_SSE, "/sse" },
+ /* 227 */ { ud_itab__227, UD_TAB__OPC_MOD, "/mod" },
+ /* 228 */ { ud_itab__228, UD_TAB__OPC_REG, "/reg" },
+ /* 229 */ { ud_itab__229, UD_TAB__OPC_OSIZE, "/o" },
+ /* 230 */ { ud_itab__230, UD_TAB__OPC_SSE, "/sse" },
+ /* 231 */ { ud_itab__231, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 232 */ { ud_itab__232, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 233 */ { ud_itab__233, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 234 */ { ud_itab__234, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 235 */ { ud_itab__235, UD_TAB__OPC_REG, "/reg" },
+ /* 236 */ { ud_itab__236, UD_TAB__OPC_SSE, "/sse" },
+ /* 237 */ { ud_itab__237, UD_TAB__OPC_SSE, "/sse" },
+ /* 238 */ { ud_itab__238, UD_TAB__OPC_SSE, "/sse" },
+ /* 239 */ { ud_itab__239, UD_TAB__OPC_SSE, "/sse" },
+ /* 240 */ { ud_itab__240, UD_TAB__OPC_SSE, "/sse" },
+ /* 241 */ { ud_itab__241, UD_TAB__OPC_SSE, "/sse" },
+ /* 242 */ { ud_itab__242, UD_TAB__OPC_SSE, "/sse" },
+ /* 243 */ { ud_itab__243, UD_TAB__OPC_SSE, "/sse" },
+ /* 244 */ { ud_itab__244, UD_TAB__OPC_SSE, "/sse" },
+ /* 245 */ { ud_itab__245, UD_TAB__OPC_SSE, "/sse" },
+ /* 246 */ { ud_itab__246, UD_TAB__OPC_SSE, "/sse" },
+ /* 247 */ { ud_itab__247, UD_TAB__OPC_SSE, "/sse" },
+ /* 248 */ { ud_itab__248, UD_TAB__OPC_SSE, "/sse" },
+ /* 249 */ { ud_itab__249, UD_TAB__OPC_SSE, "/sse" },
+ /* 250 */ { ud_itab__250, UD_TAB__OPC_SSE, "/sse" },
+ /* 251 */ { ud_itab__251, UD_TAB__OPC_SSE, "/sse" },
+ /* 252 */ { ud_itab__252, UD_TAB__OPC_SSE, "/sse" },
+ /* 253 */ { ud_itab__253, UD_TAB__OPC_SSE, "/sse" },
+ /* 254 */ { ud_itab__254, UD_TAB__OPC_SSE, "/sse" },
+ /* 255 */ { ud_itab__255, UD_TAB__OPC_SSE, "/sse" },
+ /* 256 */ { ud_itab__256, UD_TAB__OPC_SSE, "/sse" },
+ /* 257 */ { ud_itab__257, UD_TAB__OPC_SSE, "/sse" },
+ /* 258 */ { ud_itab__258, UD_TAB__OPC_SSE, "/sse" },
+ /* 259 */ { ud_itab__259, UD_TAB__OPC_SSE, "/sse" },
+ /* 260 */ { ud_itab__260, UD_TAB__OPC_SSE, "/sse" },
+ /* 261 */ { ud_itab__261, UD_TAB__OPC_SSE, "/sse" },
+ /* 262 */ { ud_itab__262, UD_TAB__OPC_SSE, "/sse" },
+ /* 263 */ { ud_itab__263, UD_TAB__OPC_SSE, "/sse" },
+ /* 264 */ { ud_itab__264, UD_TAB__OPC_SSE, "/sse" },
+ /* 265 */ { ud_itab__265, UD_TAB__OPC_SSE, "/sse" },
+ /* 266 */ { ud_itab__266, UD_TAB__OPC_SSE, "/sse" },
+ /* 267 */ { ud_itab__267, UD_TAB__OPC_SSE, "/sse" },
+ /* 268 */ { ud_itab__268, UD_TAB__OPC_SSE, "/sse" },
+ /* 269 */ { ud_itab__269, UD_TAB__OPC_SSE, "/sse" },
+ /* 270 */ { ud_itab__270, UD_TAB__OPC_SSE, "/sse" },
+ /* 271 */ { ud_itab__271, UD_TAB__OPC_SSE, "/sse" },
+ /* 272 */ { ud_itab__272, UD_TAB__OPC_SSE, "/sse" },
+ /* 273 */ { ud_itab__273, UD_TAB__OPC_SSE, "/sse" },
+ /* 274 */ { ud_itab__274, UD_TAB__OPC_SSE, "/sse" },
+ /* 275 */ { ud_itab__275, UD_TAB__OPC_MOD, "/mod" },
+ /* 276 */ { ud_itab__276, UD_TAB__OPC_SSE, "/sse" },
+ /* 277 */ { ud_itab__277, UD_TAB__OPC_SSE, "/sse" },
+ /* 278 */ { ud_itab__278, UD_TAB__OPC_SSE, "/sse" },
+ /* 279 */ { ud_itab__279, UD_TAB__OPC_SSE, "/sse" },
+ /* 280 */ { ud_itab__280, UD_TAB__OPC_SSE, "/sse" },
+ /* 281 */ { ud_itab__281, UD_TAB__OPC_SSE, "/sse" },
+ /* 282 */ { ud_itab__282, UD_TAB__OPC_SSE, "/sse" },
+ /* 283 */ { ud_itab__283, UD_TAB__OPC_SSE, "/sse" },
+ /* 284 */ { ud_itab__284, UD_TAB__OPC_MODE, "/m" },
+ /* 285 */ { ud_itab__285, UD_TAB__OPC_MODE, "/m" },
+ /* 286 */ { ud_itab__286, UD_TAB__OPC_MODE, "/m" },
+ /* 287 */ { ud_itab__287, UD_TAB__OPC_MODE, "/m" },
+ /* 288 */ { ud_itab__288, UD_TAB__OPC_MODE, "/m" },
+ /* 289 */ { ud_itab__289, UD_TAB__OPC_MODE, "/m" },
+ /* 290 */ { ud_itab__290, UD_TAB__OPC_MODE, "/m" },
+ /* 291 */ { ud_itab__291, UD_TAB__OPC_MODE, "/m" },
+ /* 292 */ { ud_itab__292, UD_TAB__OPC_OSIZE, "/o" },
+ /* 293 */ { ud_itab__293, UD_TAB__OPC_MODE, "/m" },
+ /* 294 */ { ud_itab__294, UD_TAB__OPC_MODE, "/m" },
+ /* 295 */ { ud_itab__295, UD_TAB__OPC_OSIZE, "/o" },
+ /* 296 */ { ud_itab__296, UD_TAB__OPC_MODE, "/m" },
+ /* 297 */ { ud_itab__297, UD_TAB__OPC_MODE, "/m" },
+ /* 298 */ { ud_itab__298, UD_TAB__OPC_MODE, "/m" },
+ /* 299 */ { ud_itab__299, UD_TAB__OPC_MODE, "/m" },
+ /* 300 */ { ud_itab__300, UD_TAB__OPC_OSIZE, "/o" },
+ /* 301 */ { ud_itab__301, UD_TAB__OPC_OSIZE, "/o" },
+ /* 302 */ { ud_itab__302, UD_TAB__OPC_REG, "/reg" },
+ /* 303 */ { ud_itab__303, UD_TAB__OPC_REG, "/reg" },
+ /* 304 */ { ud_itab__304, UD_TAB__OPC_REG, "/reg" },
+ /* 305 */ { ud_itab__305, UD_TAB__OPC_MODE, "/m" },
+ /* 306 */ { ud_itab__306, UD_TAB__OPC_MODE, "/m" },
+ /* 307 */ { ud_itab__307, UD_TAB__OPC_MODE, "/m" },
+ /* 308 */ { ud_itab__308, UD_TAB__OPC_MODE, "/m" },
+ /* 309 */ { ud_itab__309, UD_TAB__OPC_MODE, "/m" },
+ /* 310 */ { ud_itab__310, UD_TAB__OPC_MODE, "/m" },
+ /* 311 */ { ud_itab__311, UD_TAB__OPC_MODE, "/m" },
+ /* 312 */ { ud_itab__312, UD_TAB__OPC_MODE, "/m" },
+ /* 313 */ { ud_itab__313, UD_TAB__OPC_REG, "/reg" },
+ /* 314 */ { ud_itab__314, UD_TAB__OPC_REG, "/reg" },
+ /* 315 */ { ud_itab__315, UD_TAB__OPC_OSIZE, "/o" },
+ /* 316 */ { ud_itab__316, UD_TAB__OPC_OSIZE, "/o" },
+ /* 317 */ { ud_itab__317, UD_TAB__OPC_MODE, "/m" },
+ /* 318 */ { ud_itab__318, UD_TAB__OPC_OSIZE, "/o" },
+ /* 319 */ { ud_itab__319, UD_TAB__OPC_MODE, "/m" },
+ /* 320 */ { ud_itab__320, UD_TAB__OPC_MODE, "/m" },
+ /* 321 */ { ud_itab__321, UD_TAB__OPC_MODE, "/m" },
+ /* 322 */ { ud_itab__322, UD_TAB__OPC_OSIZE, "/o" },
+ /* 323 */ { ud_itab__323, UD_TAB__OPC_MODE, "/m" },
+ /* 324 */ { ud_itab__324, UD_TAB__OPC_MODE, "/m" },
+ /* 325 */ { ud_itab__325, UD_TAB__OPC_MODE, "/m" },
+ /* 326 */ { ud_itab__326, UD_TAB__OPC_OSIZE, "/o" },
+ /* 327 */ { ud_itab__327, UD_TAB__OPC_OSIZE, "/o" },
+ /* 328 */ { ud_itab__328, UD_TAB__OPC_OSIZE, "/o" },
+ /* 329 */ { ud_itab__329, UD_TAB__OPC_OSIZE, "/o" },
+ /* 330 */ { ud_itab__330, UD_TAB__OPC_OSIZE, "/o" },
+ /* 331 */ { ud_itab__331, UD_TAB__OPC_REG, "/reg" },
+ /* 332 */ { ud_itab__332, UD_TAB__OPC_REG, "/reg" },
+ /* 333 */ { ud_itab__333, UD_TAB__OPC_VEX, "/vex" },
+ /* 334 */ { ud_itab__334, UD_TAB__OPC_MODE, "/m" },
+ /* 335 */ { ud_itab__335, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 336 */ { ud_itab__336, UD_TAB__OPC_MOD, "/mod" },
+ /* 337 */ { ud_itab__337, UD_TAB__OPC_MOD, "/mod" },
+ /* 338 */ { ud_itab__338, UD_TAB__OPC_MOD, "/mod" },
+ /* 339 */ { ud_itab__339, UD_TAB__OPC_REG, "/reg" },
+ /* 340 */ { ud_itab__340, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 341 */ { ud_itab__341, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 342 */ { ud_itab__342, UD_TAB__OPC_MOD, "/mod" },
+ /* 343 */ { ud_itab__343, UD_TAB__OPC_MOD, "/mod" },
+ /* 344 */ { ud_itab__344, UD_TAB__OPC_OSIZE, "/o" },
+ /* 345 */ { ud_itab__345, UD_TAB__OPC_REG, "/reg" },
+ /* 346 */ { ud_itab__346, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 347 */ { ud_itab__347, UD_TAB__OPC_REG, "/reg" },
+ /* 348 */ { ud_itab__348, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 349 */ { ud_itab__349, UD_TAB__OPC_REG, "/reg" },
+ /* 350 */ { ud_itab__350, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 351 */ { ud_itab__351, UD_TAB__OPC_OSIZE, "/o" },
+ /* 352 */ { ud_itab__352, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 353 */ { ud_itab__353, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 354 */ { ud_itab__354, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 355 */ { ud_itab__355, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 356 */ { ud_itab__356, UD_TAB__OPC_MOD, "/mod" },
+ /* 357 */ { ud_itab__357, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 358 */ { ud_itab__358, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 359 */ { ud_itab__359, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 360 */ { ud_itab__360, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 361 */ { ud_itab__361, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 362 */ { ud_itab__362, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 363 */ { ud_itab__363, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 364 */ { ud_itab__364, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 365 */ { ud_itab__365, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 366 */ { ud_itab__366, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 367 */ { ud_itab__367, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 368 */ { ud_itab__368, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 369 */ { ud_itab__369, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 370 */ { ud_itab__370, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 371 */ { ud_itab__371, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 372 */ { ud_itab__372, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 373 */ { ud_itab__373, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 374 */ { ud_itab__374, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 375 */ { ud_itab__375, UD_TAB__OPC_OSIZE, "/o" },
+ /* 376 */ { ud_itab__376, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 377 */ { ud_itab__377, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 378 */ { ud_itab__378, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 379 */ { ud_itab__379, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 380 */ { ud_itab__380, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 381 */ { ud_itab__381, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 382 */ { ud_itab__382, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 383 */ { ud_itab__383, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 384 */ { ud_itab__384, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 385 */ { ud_itab__385, UD_TAB__OPC_MODE, "/m" },
+ /* 386 */ { ud_itab__386, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 387 */ { ud_itab__387, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 388 */ { ud_itab__388, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 389 */ { ud_itab__389, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 390 */ { ud_itab__390, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 391 */ { ud_itab__391, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 392 */ { ud_itab__392, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 393 */ { ud_itab__393, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 394 */ { ud_itab__394, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 395 */ { ud_itab__395, UD_TAB__OPC_MOD, "/mod" },
+ /* 396 */ { ud_itab__396, UD_TAB__OPC_MOD, "/mod" },
+ /* 397 */ { ud_itab__397, UD_TAB__OPC_MOD, "/mod" },
+ /* 398 */ { ud_itab__398, UD_TAB__OPC_MOD, "/mod" },
+ /* 399 */ { ud_itab__399, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 400 */ { ud_itab__400, UD_TAB__OPC_MOD, "/mod" },
+ /* 401 */ { ud_itab__401, UD_TAB__OPC_MOD, "/mod" },
+ /* 402 */ { ud_itab__402, UD_TAB__OPC_MOD, "/mod" },
+ /* 403 */ { ud_itab__403, UD_TAB__OPC_VEX, "/vex" },
+ /* 404 */ { ud_itab__404, UD_TAB__OPC_MODE, "/m" },
+ /* 405 */ { ud_itab__405, UD_TAB__OPC_REG, "/reg" },
+ /* 406 */ { ud_itab__406, UD_TAB__OPC_REG, "/reg" },
+ /* 407 */ { ud_itab__407, UD_TAB__OPC_MODE, "/m" },
+ /* 408 */ { ud_itab__408, UD_TAB__OPC_OSIZE, "/o" },
+ /* 409 */ { ud_itab__409, UD_TAB__OPC_REG, "/reg" },
+ /* 410 */ { ud_itab__410, UD_TAB__OPC_REG, "/reg" },
+ /* 411 */ { ud_itab__411, UD_TAB__OPC_REG, "/reg" },
+ /* 412 */ { ud_itab__412, UD_TAB__OPC_REG, "/reg" },
+ /* 413 */ { ud_itab__413, UD_TAB__OPC_MODE, "/m" },
+ /* 414 */ { ud_itab__414, UD_TAB__OPC_MODE, "/m" },
+ /* 415 */ { ud_itab__415, UD_TAB__OPC_MODE, "/m" },
+ /* 416 */ { ud_itab__416, UD_TAB__OPC_MOD, "/mod" },
+ /* 417 */ { ud_itab__417, UD_TAB__OPC_REG, "/reg" },
+ /* 418 */ { ud_itab__418, UD_TAB__OPC_X87, "/x87" },
+ /* 419 */ { ud_itab__419, UD_TAB__OPC_MOD, "/mod" },
+ /* 420 */ { ud_itab__420, UD_TAB__OPC_REG, "/reg" },
+ /* 421 */ { ud_itab__421, UD_TAB__OPC_X87, "/x87" },
+ /* 422 */ { ud_itab__422, UD_TAB__OPC_MOD, "/mod" },
+ /* 423 */ { ud_itab__423, UD_TAB__OPC_REG, "/reg" },
+ /* 424 */ { ud_itab__424, UD_TAB__OPC_X87, "/x87" },
+ /* 425 */ { ud_itab__425, UD_TAB__OPC_MOD, "/mod" },
+ /* 426 */ { ud_itab__426, UD_TAB__OPC_REG, "/reg" },
+ /* 427 */ { ud_itab__427, UD_TAB__OPC_X87, "/x87" },
+ /* 428 */ { ud_itab__428, UD_TAB__OPC_MOD, "/mod" },
+ /* 429 */ { ud_itab__429, UD_TAB__OPC_REG, "/reg" },
+ /* 430 */ { ud_itab__430, UD_TAB__OPC_X87, "/x87" },
+ /* 431 */ { ud_itab__431, UD_TAB__OPC_MOD, "/mod" },
+ /* 432 */ { ud_itab__432, UD_TAB__OPC_REG, "/reg" },
+ /* 433 */ { ud_itab__433, UD_TAB__OPC_X87, "/x87" },
+ /* 434 */ { ud_itab__434, UD_TAB__OPC_MOD, "/mod" },
+ /* 435 */ { ud_itab__435, UD_TAB__OPC_REG, "/reg" },
+ /* 436 */ { ud_itab__436, UD_TAB__OPC_X87, "/x87" },
+ /* 437 */ { ud_itab__437, UD_TAB__OPC_MOD, "/mod" },
+ /* 438 */ { ud_itab__438, UD_TAB__OPC_REG, "/reg" },
+ /* 439 */ { ud_itab__439, UD_TAB__OPC_X87, "/x87" },
+ /* 440 */ { ud_itab__440, UD_TAB__OPC_ASIZE, "/a" },
+ /* 441 */ { ud_itab__441, UD_TAB__OPC_MODE, "/m" },
+ /* 442 */ { ud_itab__442, UD_TAB__OPC_REG, "/reg" },
+ /* 443 */ { ud_itab__443, UD_TAB__OPC_REG, "/reg" },
+ /* 444 */ { ud_itab__444, UD_TAB__OPC_REG, "/reg" },
+ /* 445 */ { ud_itab__445, UD_TAB__OPC_REG, "/reg" },
+ /* 446 */ { ud_itab__446, UD_TAB__OPC_MODE, "/m" },
+};
+
+/* itab entry operand definitions (for readability) */
+#define O_AL { OP_AL, SZ_B }
+#define O_AX { OP_AX, SZ_W }
+#define O_Av { OP_A, SZ_V }
+#define O_C { OP_C, SZ_NA }
+#define O_CL { OP_CL, SZ_B }
+#define O_CS { OP_CS, SZ_NA }
+#define O_CX { OP_CX, SZ_W }
+#define O_D { OP_D, SZ_NA }
+#define O_DL { OP_DL, SZ_B }
+#define O_DS { OP_DS, SZ_NA }
+#define O_DX { OP_DX, SZ_W }
+#define O_E { OP_E, SZ_NA }
+#define O_ES { OP_ES, SZ_NA }
+#define O_Eb { OP_E, SZ_B }
+#define O_Ed { OP_E, SZ_D }
+#define O_Eq { OP_E, SZ_Q }
+#define O_Ev { OP_E, SZ_V }
+#define O_Ew { OP_E, SZ_W }
+#define O_Ey { OP_E, SZ_Y }
+#define O_Ez { OP_E, SZ_Z }
+#define O_FS { OP_FS, SZ_NA }
+#define O_Fv { OP_F, SZ_V }
+#define O_G { OP_G, SZ_NA }
+#define O_GS { OP_GS, SZ_NA }
+#define O_Gb { OP_G, SZ_B }
+#define O_Gd { OP_G, SZ_D }
+#define O_Gq { OP_G, SZ_Q }
+#define O_Gv { OP_G, SZ_V }
+#define O_Gw { OP_G, SZ_W }
+#define O_Gy { OP_G, SZ_Y }
+#define O_Gz { OP_G, SZ_Z }
+#define O_H { OP_H, SZ_X }
+#define O_Hqq { OP_H, SZ_QQ }
+#define O_Hx { OP_H, SZ_X }
+#define O_I1 { OP_I1, SZ_NA }
+#define O_I3 { OP_I3, SZ_NA }
+#define O_Ib { OP_I, SZ_B }
+#define O_Iv { OP_I, SZ_V }
+#define O_Iw { OP_I, SZ_W }
+#define O_Iz { OP_I, SZ_Z }
+#define O_Jb { OP_J, SZ_B }
+#define O_Jv { OP_J, SZ_V }
+#define O_Jz { OP_J, SZ_Z }
+#define O_L { OP_L, SZ_O }
+#define O_Lx { OP_L, SZ_X }
+#define O_M { OP_M, SZ_NA }
+#define O_Mb { OP_M, SZ_B }
+#define O_MbRd { OP_MR, SZ_BD }
+#define O_MbRv { OP_MR, SZ_BV }
+#define O_Md { OP_M, SZ_D }
+#define O_MdRy { OP_MR, SZ_DY }
+#define O_MdU { OP_MU, SZ_DO }
+#define O_Mdq { OP_M, SZ_DQ }
+#define O_Mo { OP_M, SZ_O }
+#define O_Mq { OP_M, SZ_Q }
+#define O_MqU { OP_MU, SZ_QO }
+#define O_Ms { OP_M, SZ_W }
+#define O_Mt { OP_M, SZ_T }
+#define O_Mv { OP_M, SZ_V }
+#define O_Mw { OP_M, SZ_W }
+#define O_MwRd { OP_MR, SZ_WD }
+#define O_MwRv { OP_MR, SZ_WV }
+#define O_MwRy { OP_MR, SZ_WY }
+#define O_MwU { OP_MU, SZ_WO }
+#define O_N { OP_N, SZ_Q }
+#define O_NONE { OP_NONE, SZ_NA }
+#define O_Ob { OP_O, SZ_B }
+#define O_Ov { OP_O, SZ_V }
+#define O_Ow { OP_O, SZ_W }
+#define O_P { OP_P, SZ_Q }
+#define O_Q { OP_Q, SZ_Q }
+#define O_R { OP_R, SZ_RDQ }
+#define O_R0b { OP_R0, SZ_B }
+#define O_R0v { OP_R0, SZ_V }
+#define O_R0w { OP_R0, SZ_W }
+#define O_R0y { OP_R0, SZ_Y }
+#define O_R0z { OP_R0, SZ_Z }
+#define O_R1b { OP_R1, SZ_B }
+#define O_R1v { OP_R1, SZ_V }
+#define O_R1w { OP_R1, SZ_W }
+#define O_R1y { OP_R1, SZ_Y }
+#define O_R1z { OP_R1, SZ_Z }
+#define O_R2b { OP_R2, SZ_B }
+#define O_R2v { OP_R2, SZ_V }
+#define O_R2w { OP_R2, SZ_W }
+#define O_R2y { OP_R2, SZ_Y }
+#define O_R2z { OP_R2, SZ_Z }
+#define O_R3b { OP_R3, SZ_B }
+#define O_R3v { OP_R3, SZ_V }
+#define O_R3w { OP_R3, SZ_W }
+#define O_R3y { OP_R3, SZ_Y }
+#define O_R3z { OP_R3, SZ_Z }
+#define O_R4b { OP_R4, SZ_B }
+#define O_R4v { OP_R4, SZ_V }
+#define O_R4w { OP_R4, SZ_W }
+#define O_R4y { OP_R4, SZ_Y }
+#define O_R4z { OP_R4, SZ_Z }
+#define O_R5b { OP_R5, SZ_B }
+#define O_R5v { OP_R5, SZ_V }
+#define O_R5w { OP_R5, SZ_W }
+#define O_R5y { OP_R5, SZ_Y }
+#define O_R5z { OP_R5, SZ_Z }
+#define O_R6b { OP_R6, SZ_B }
+#define O_R6v { OP_R6, SZ_V }
+#define O_R6w { OP_R6, SZ_W }
+#define O_R6y { OP_R6, SZ_Y }
+#define O_R6z { OP_R6, SZ_Z }
+#define O_R7b { OP_R7, SZ_B }
+#define O_R7v { OP_R7, SZ_V }
+#define O_R7w { OP_R7, SZ_W }
+#define O_R7y { OP_R7, SZ_Y }
+#define O_R7z { OP_R7, SZ_Z }
+#define O_S { OP_S, SZ_W }
+#define O_SS { OP_SS, SZ_NA }
+#define O_ST0 { OP_ST0, SZ_NA }
+#define O_ST1 { OP_ST1, SZ_NA }
+#define O_ST2 { OP_ST2, SZ_NA }
+#define O_ST3 { OP_ST3, SZ_NA }
+#define O_ST4 { OP_ST4, SZ_NA }
+#define O_ST5 { OP_ST5, SZ_NA }
+#define O_ST6 { OP_ST6, SZ_NA }
+#define O_ST7 { OP_ST7, SZ_NA }
+#define O_U { OP_U, SZ_O }
+#define O_Ux { OP_U, SZ_X }
+#define O_V { OP_V, SZ_DQ }
+#define O_Vdq { OP_V, SZ_DQ }
+#define O_Vqq { OP_V, SZ_QQ }
+#define O_Vsd { OP_V, SZ_Q }
+#define O_Vx { OP_V, SZ_X }
+#define O_W { OP_W, SZ_DQ }
+#define O_Wdq { OP_W, SZ_DQ }
+#define O_Wqq { OP_W, SZ_QQ }
+#define O_Wsd { OP_W, SZ_Q }
+#define O_Wx { OP_W, SZ_X }
+#define O_eAX { OP_eAX, SZ_Z }
+#define O_eCX { OP_eCX, SZ_Z }
+#define O_eDX { OP_eDX, SZ_Z }
+#define O_rAX { OP_rAX, SZ_V }
+#define O_rCX { OP_rCX, SZ_V }
+#define O_rDX { OP_rDX, SZ_V }
+#define O_sIb { OP_sI, SZ_B }
+#define O_sIv { OP_sI, SZ_V }
+#define O_sIz { OP_sI, SZ_Z }
+
+struct ud_itab_entry ud_itab[] = {
+ /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0001 */ { UD_Iaaa, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0002 */ { UD_Iaad, O_Ib, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0003 */ { UD_Iaam, O_Ib, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0004 */ { UD_Iaas, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0005 */ { UD_Iadc, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0006 */ { UD_Iadc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0007 */ { UD_Iadc, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0008 */ { UD_Iadc, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0009 */ { UD_Iadc, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0010 */ { UD_Iadc, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0011 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0012 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0013 */ { UD_Iadc, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0014 */ { UD_Iadc, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0015 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0016 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0017 */ { UD_Iadd, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0018 */ { UD_Iadd, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0019 */ { UD_Iadd, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0020 */ { UD_Iadd, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0021 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0022 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0023 */ { UD_Iadd, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0024 */ { UD_Iadd, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0025 */ { UD_Iaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0026 */ { UD_Ivaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0027 */ { UD_Iaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0028 */ { UD_Ivaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0029 */ { UD_Iaddsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0030 */ { UD_Ivaddsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0031 */ { UD_Iaddss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0032 */ { UD_Ivaddss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0033 */ { UD_Iaddsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0034 */ { UD_Ivaddsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0035 */ { UD_Iaddsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0036 */ { UD_Ivaddsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0037 */ { UD_Iaesdec, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0038 */ { UD_Ivaesdec, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0039 */ { UD_Iaesdeclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0040 */ { UD_Ivaesdeclast, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0041 */ { UD_Iaesenc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0042 */ { UD_Ivaesenc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0043 */ { UD_Iaesenclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0044 */ { UD_Ivaesenclast, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0045 */ { UD_Iaesimc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0046 */ { UD_Ivaesimc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0047 */ { UD_Iaeskeygenassist, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0048 */ { UD_Ivaeskeygenassist, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0049 */ { UD_Iand, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0050 */ { UD_Iand, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0051 */ { UD_Iand, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0052 */ { UD_Iand, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0053 */ { UD_Iand, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0054 */ { UD_Iand, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0055 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0056 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0057 */ { UD_Iand, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0058 */ { UD_Iand, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0059 */ { UD_Iandpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0060 */ { UD_Ivandpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0061 */ { UD_Iandps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0062 */ { UD_Ivandps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0063 */ { UD_Iandnpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0064 */ { UD_Ivandnpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0065 */ { UD_Iandnps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0066 */ { UD_Ivandnps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0067 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, O_NONE, P_aso },
+ /* 0068 */ { UD_Imovsxd, O_Gq, O_Ed, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexx|P_rexr|P_rexb },
+ /* 0069 */ { UD_Icall, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0070 */ { UD_Icall, O_Eq, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 0071 */ { UD_Icall, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0072 */ { UD_Icall, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0073 */ { UD_Icall, O_Av, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0074 */ { UD_Icbw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0075 */ { UD_Icwde, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0076 */ { UD_Icdqe, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0077 */ { UD_Iclc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0078 */ { UD_Icld, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0079 */ { UD_Iclflush, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0080 */ { UD_Iclgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0081 */ { UD_Icli, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0082 */ { UD_Iclts, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0083 */ { UD_Icmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0084 */ { UD_Icmovo, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0085 */ { UD_Icmovno, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0086 */ { UD_Icmovb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0087 */ { UD_Icmovae, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0088 */ { UD_Icmovz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0089 */ { UD_Icmovnz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0090 */ { UD_Icmovbe, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0091 */ { UD_Icmova, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0092 */ { UD_Icmovs, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0093 */ { UD_Icmovns, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0094 */ { UD_Icmovp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0095 */ { UD_Icmovnp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0096 */ { UD_Icmovl, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0097 */ { UD_Icmovge, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0098 */ { UD_Icmovle, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0099 */ { UD_Icmovg, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0100 */ { UD_Icmp, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0101 */ { UD_Icmp, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0102 */ { UD_Icmp, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0103 */ { UD_Icmp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0104 */ { UD_Icmp, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0105 */ { UD_Icmp, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0106 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0107 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0108 */ { UD_Icmp, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0109 */ { UD_Icmp, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0110 */ { UD_Icmppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0111 */ { UD_Ivcmppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0112 */ { UD_Icmpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0113 */ { UD_Ivcmpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0114 */ { UD_Icmpsb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_seg },
+ /* 0115 */ { UD_Icmpsw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg },
+ /* 0116 */ { UD_Icmpsd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg },
+ /* 0117 */ { UD_Icmpsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0118 */ { UD_Ivcmpsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0119 */ { UD_Icmpsq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg },
+ /* 0120 */ { UD_Icmpss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0121 */ { UD_Ivcmpss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0122 */ { UD_Icmpxchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0123 */ { UD_Icmpxchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0124 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0125 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0126 */ { UD_Icmpxchg16b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0127 */ { UD_Icomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0128 */ { UD_Ivcomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0129 */ { UD_Icomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0130 */ { UD_Ivcomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0131 */ { UD_Icpuid, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0132 */ { UD_Icvtdq2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0133 */ { UD_Ivcvtdq2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0134 */ { UD_Icvtdq2ps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0135 */ { UD_Ivcvtdq2ps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0136 */ { UD_Icvtpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0137 */ { UD_Ivcvtpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0138 */ { UD_Icvtpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0139 */ { UD_Icvtpd2ps, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0140 */ { UD_Ivcvtpd2ps, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0141 */ { UD_Icvtpi2ps, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0142 */ { UD_Icvtpi2pd, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0143 */ { UD_Icvtps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0144 */ { UD_Ivcvtps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0145 */ { UD_Icvtps2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0146 */ { UD_Ivcvtps2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0147 */ { UD_Icvtps2pi, O_P, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0148 */ { UD_Icvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0149 */ { UD_Ivcvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0150 */ { UD_Icvtsd2ss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0151 */ { UD_Ivcvtsd2ss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0152 */ { UD_Icvtsi2sd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0153 */ { UD_Ivcvtsi2sd, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0154 */ { UD_Icvtsi2ss, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0155 */ { UD_Ivcvtsi2ss, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0156 */ { UD_Icvtss2sd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0157 */ { UD_Ivcvtss2sd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0158 */ { UD_Icvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0159 */ { UD_Ivcvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0160 */ { UD_Icvttpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0161 */ { UD_Ivcvttpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0162 */ { UD_Icvttpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0163 */ { UD_Icvttps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0164 */ { UD_Ivcvttps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0165 */ { UD_Icvttps2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0166 */ { UD_Icvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0167 */ { UD_Ivcvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0168 */ { UD_Icvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0169 */ { UD_Ivcvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0170 */ { UD_Icwd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0171 */ { UD_Icdq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0172 */ { UD_Icqo, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0173 */ { UD_Idaa, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 0174 */ { UD_Idas, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 0175 */ { UD_Idec, O_R0z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0176 */ { UD_Idec, O_R1z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0177 */ { UD_Idec, O_R2z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0178 */ { UD_Idec, O_R3z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0179 */ { UD_Idec, O_R4z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0180 */ { UD_Idec, O_R5z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0181 */ { UD_Idec, O_R6z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0182 */ { UD_Idec, O_R7z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0183 */ { UD_Idec, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0184 */ { UD_Idec, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0185 */ { UD_Idiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0186 */ { UD_Idiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0187 */ { UD_Idivpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0188 */ { UD_Ivdivpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0189 */ { UD_Idivps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0190 */ { UD_Ivdivps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0191 */ { UD_Idivsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0192 */ { UD_Ivdivsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0193 */ { UD_Idivss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0194 */ { UD_Ivdivss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0195 */ { UD_Idppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0196 */ { UD_Ivdppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0197 */ { UD_Idpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0198 */ { UD_Ivdpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0199 */ { UD_Iemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0200 */ { UD_Ienter, O_Iw, O_Ib, O_NONE, O_NONE, P_def64 },
+ /* 0201 */ { UD_Iextractps, O_MdRy, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 0202 */ { UD_Ivextractps, O_MdRy, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 0203 */ { UD_If2xm1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0204 */ { UD_Ifabs, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0205 */ { UD_Ifadd, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0206 */ { UD_Ifadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0207 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0208 */ { UD_Ifadd, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0209 */ { UD_Ifadd, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0210 */ { UD_Ifadd, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0211 */ { UD_Ifadd, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0212 */ { UD_Ifadd, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0213 */ { UD_Ifadd, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0214 */ { UD_Ifadd, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0215 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0216 */ { UD_Ifadd, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0217 */ { UD_Ifadd, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0218 */ { UD_Ifadd, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0219 */ { UD_Ifadd, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0220 */ { UD_Ifadd, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0221 */ { UD_Ifadd, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0222 */ { UD_Ifadd, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0223 */ { UD_Ifaddp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0224 */ { UD_Ifaddp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0225 */ { UD_Ifaddp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0226 */ { UD_Ifaddp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0227 */ { UD_Ifaddp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0228 */ { UD_Ifaddp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0229 */ { UD_Ifaddp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0230 */ { UD_Ifaddp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0231 */ { UD_Ifbld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0232 */ { UD_Ifbstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0233 */ { UD_Ifchs, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0234 */ { UD_Ifclex, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0235 */ { UD_Ifcmovb, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0236 */ { UD_Ifcmovb, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0237 */ { UD_Ifcmovb, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0238 */ { UD_Ifcmovb, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0239 */ { UD_Ifcmovb, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0240 */ { UD_Ifcmovb, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0241 */ { UD_Ifcmovb, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0242 */ { UD_Ifcmovb, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0243 */ { UD_Ifcmove, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0244 */ { UD_Ifcmove, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0245 */ { UD_Ifcmove, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0246 */ { UD_Ifcmove, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0247 */ { UD_Ifcmove, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0248 */ { UD_Ifcmove, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0249 */ { UD_Ifcmove, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0250 */ { UD_Ifcmove, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0251 */ { UD_Ifcmovbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0252 */ { UD_Ifcmovbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0253 */ { UD_Ifcmovbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0254 */ { UD_Ifcmovbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0255 */ { UD_Ifcmovbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0256 */ { UD_Ifcmovbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0257 */ { UD_Ifcmovbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0258 */ { UD_Ifcmovbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0259 */ { UD_Ifcmovu, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0260 */ { UD_Ifcmovu, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0261 */ { UD_Ifcmovu, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0262 */ { UD_Ifcmovu, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0263 */ { UD_Ifcmovu, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0264 */ { UD_Ifcmovu, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0265 */ { UD_Ifcmovu, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0266 */ { UD_Ifcmovu, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0267 */ { UD_Ifcmovnb, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0268 */ { UD_Ifcmovnb, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0269 */ { UD_Ifcmovnb, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0270 */ { UD_Ifcmovnb, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0271 */ { UD_Ifcmovnb, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0272 */ { UD_Ifcmovnb, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0273 */ { UD_Ifcmovnb, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0274 */ { UD_Ifcmovnb, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0275 */ { UD_Ifcmovne, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0276 */ { UD_Ifcmovne, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0277 */ { UD_Ifcmovne, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0278 */ { UD_Ifcmovne, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0279 */ { UD_Ifcmovne, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0280 */ { UD_Ifcmovne, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0281 */ { UD_Ifcmovne, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0282 */ { UD_Ifcmovne, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0283 */ { UD_Ifcmovnbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0284 */ { UD_Ifcmovnbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0285 */ { UD_Ifcmovnbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0286 */ { UD_Ifcmovnbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0287 */ { UD_Ifcmovnbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0288 */ { UD_Ifcmovnbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0289 */ { UD_Ifcmovnbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0290 */ { UD_Ifcmovnbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0291 */ { UD_Ifcmovnu, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0292 */ { UD_Ifcmovnu, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0293 */ { UD_Ifcmovnu, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0294 */ { UD_Ifcmovnu, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0295 */ { UD_Ifcmovnu, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0296 */ { UD_Ifcmovnu, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0297 */ { UD_Ifcmovnu, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0298 */ { UD_Ifcmovnu, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0299 */ { UD_Ifucomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0300 */ { UD_Ifucomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0301 */ { UD_Ifucomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0302 */ { UD_Ifucomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0303 */ { UD_Ifucomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0304 */ { UD_Ifucomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0305 */ { UD_Ifucomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0306 */ { UD_Ifucomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0307 */ { UD_Ifcom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0308 */ { UD_Ifcom, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0309 */ { UD_Ifcom, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0310 */ { UD_Ifcom, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0311 */ { UD_Ifcom, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0312 */ { UD_Ifcom, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0313 */ { UD_Ifcom, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0314 */ { UD_Ifcom, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0315 */ { UD_Ifcom, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0316 */ { UD_Ifcom, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0317 */ { UD_Ifcom2, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0318 */ { UD_Ifcom2, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0319 */ { UD_Ifcom2, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0320 */ { UD_Ifcom2, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0321 */ { UD_Ifcom2, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0322 */ { UD_Ifcom2, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0323 */ { UD_Ifcom2, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0324 */ { UD_Ifcom2, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0325 */ { UD_Ifcomp3, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0326 */ { UD_Ifcomp3, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0327 */ { UD_Ifcomp3, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0328 */ { UD_Ifcomp3, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0329 */ { UD_Ifcomp3, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0330 */ { UD_Ifcomp3, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0331 */ { UD_Ifcomp3, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0332 */ { UD_Ifcomp3, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0333 */ { UD_Ifcomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0334 */ { UD_Ifcomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0335 */ { UD_Ifcomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0336 */ { UD_Ifcomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0337 */ { UD_Ifcomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0338 */ { UD_Ifcomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0339 */ { UD_Ifcomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0340 */ { UD_Ifcomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0341 */ { UD_Ifucomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0342 */ { UD_Ifucomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0343 */ { UD_Ifucomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0344 */ { UD_Ifucomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0345 */ { UD_Ifucomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0346 */ { UD_Ifucomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0347 */ { UD_Ifucomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0348 */ { UD_Ifucomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0349 */ { UD_Ifcomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0350 */ { UD_Ifcomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0351 */ { UD_Ifcomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0352 */ { UD_Ifcomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0353 */ { UD_Ifcomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0354 */ { UD_Ifcomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0355 */ { UD_Ifcomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0356 */ { UD_Ifcomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0357 */ { UD_Ifcomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0358 */ { UD_Ifcomp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0359 */ { UD_Ifcomp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0360 */ { UD_Ifcomp, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0361 */ { UD_Ifcomp, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0362 */ { UD_Ifcomp, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0363 */ { UD_Ifcomp, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0364 */ { UD_Ifcomp, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0365 */ { UD_Ifcomp, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0366 */ { UD_Ifcomp, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0367 */ { UD_Ifcomp5, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0368 */ { UD_Ifcomp5, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0369 */ { UD_Ifcomp5, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0370 */ { UD_Ifcomp5, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0371 */ { UD_Ifcomp5, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0372 */ { UD_Ifcomp5, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0373 */ { UD_Ifcomp5, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0374 */ { UD_Ifcomp5, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0375 */ { UD_Ifcompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0376 */ { UD_Ifcos, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0377 */ { UD_Ifdecstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0378 */ { UD_Ifdiv, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0379 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0380 */ { UD_Ifdiv, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0381 */ { UD_Ifdiv, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0382 */ { UD_Ifdiv, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0383 */ { UD_Ifdiv, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0384 */ { UD_Ifdiv, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0385 */ { UD_Ifdiv, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0386 */ { UD_Ifdiv, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0387 */ { UD_Ifdiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0388 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0389 */ { UD_Ifdiv, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0390 */ { UD_Ifdiv, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0391 */ { UD_Ifdiv, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0392 */ { UD_Ifdiv, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0393 */ { UD_Ifdiv, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0394 */ { UD_Ifdiv, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0395 */ { UD_Ifdiv, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0396 */ { UD_Ifdivp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0397 */ { UD_Ifdivp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0398 */ { UD_Ifdivp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0399 */ { UD_Ifdivp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0400 */ { UD_Ifdivp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0401 */ { UD_Ifdivp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0402 */ { UD_Ifdivp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0403 */ { UD_Ifdivp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0404 */ { UD_Ifdivr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0405 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0406 */ { UD_Ifdivr, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0407 */ { UD_Ifdivr, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0408 */ { UD_Ifdivr, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0409 */ { UD_Ifdivr, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0410 */ { UD_Ifdivr, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0411 */ { UD_Ifdivr, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0412 */ { UD_Ifdivr, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0413 */ { UD_Ifdivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0414 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0415 */ { UD_Ifdivr, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0416 */ { UD_Ifdivr, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0417 */ { UD_Ifdivr, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0418 */ { UD_Ifdivr, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0419 */ { UD_Ifdivr, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0420 */ { UD_Ifdivr, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0421 */ { UD_Ifdivr, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0422 */ { UD_Ifdivrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0423 */ { UD_Ifdivrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0424 */ { UD_Ifdivrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0425 */ { UD_Ifdivrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0426 */ { UD_Ifdivrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0427 */ { UD_Ifdivrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0428 */ { UD_Ifdivrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0429 */ { UD_Ifdivrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0430 */ { UD_Ifemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0431 */ { UD_Iffree, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0432 */ { UD_Iffree, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0433 */ { UD_Iffree, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0434 */ { UD_Iffree, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0435 */ { UD_Iffree, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0436 */ { UD_Iffree, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0437 */ { UD_Iffree, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0438 */ { UD_Iffree, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0439 */ { UD_Iffreep, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0440 */ { UD_Iffreep, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0441 */ { UD_Iffreep, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0442 */ { UD_Iffreep, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0443 */ { UD_Iffreep, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0444 */ { UD_Iffreep, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0445 */ { UD_Iffreep, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0446 */ { UD_Iffreep, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0447 */ { UD_Ificom, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0448 */ { UD_Ificom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0449 */ { UD_Ificomp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0450 */ { UD_Ificomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0451 */ { UD_Ifild, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0452 */ { UD_Ifild, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0453 */ { UD_Ifild, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0454 */ { UD_Ifincstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0455 */ { UD_Ifninit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0456 */ { UD_Ifiadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0457 */ { UD_Ifiadd, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0458 */ { UD_Ifidivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0459 */ { UD_Ifidivr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0460 */ { UD_Ifidiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0461 */ { UD_Ifidiv, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0462 */ { UD_Ifisub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0463 */ { UD_Ifisub, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0464 */ { UD_Ifisubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0465 */ { UD_Ifisubr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0466 */ { UD_Ifist, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0467 */ { UD_Ifist, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0468 */ { UD_Ifistp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0469 */ { UD_Ifistp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0470 */ { UD_Ifistp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0471 */ { UD_Ifisttp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0472 */ { UD_Ifisttp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0473 */ { UD_Ifisttp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0474 */ { UD_Ifld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0475 */ { UD_Ifld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0476 */ { UD_Ifld, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0477 */ { UD_Ifld, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0478 */ { UD_Ifld, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0479 */ { UD_Ifld, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0480 */ { UD_Ifld, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0481 */ { UD_Ifld, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0482 */ { UD_Ifld, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0483 */ { UD_Ifld, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0484 */ { UD_Ifld, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0485 */ { UD_Ifld1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0486 */ { UD_Ifldl2t, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0487 */ { UD_Ifldl2e, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0488 */ { UD_Ifldpi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0489 */ { UD_Ifldlg2, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0490 */ { UD_Ifldln2, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0491 */ { UD_Ifldz, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0492 */ { UD_Ifldcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0493 */ { UD_Ifldenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0494 */ { UD_Ifmul, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0495 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0496 */ { UD_Ifmul, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0497 */ { UD_Ifmul, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0498 */ { UD_Ifmul, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0499 */ { UD_Ifmul, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0500 */ { UD_Ifmul, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0501 */ { UD_Ifmul, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0502 */ { UD_Ifmul, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0503 */ { UD_Ifmul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0504 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0505 */ { UD_Ifmul, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0506 */ { UD_Ifmul, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0507 */ { UD_Ifmul, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0508 */ { UD_Ifmul, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0509 */ { UD_Ifmul, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0510 */ { UD_Ifmul, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0511 */ { UD_Ifmul, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0512 */ { UD_Ifmulp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0513 */ { UD_Ifmulp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0514 */ { UD_Ifmulp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0515 */ { UD_Ifmulp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0516 */ { UD_Ifmulp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0517 */ { UD_Ifmulp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0518 */ { UD_Ifmulp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0519 */ { UD_Ifmulp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0520 */ { UD_Ifimul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0521 */ { UD_Ifimul, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0522 */ { UD_Ifnop, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0523 */ { UD_Ifndisi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0524 */ { UD_Ifneni, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0525 */ { UD_Ifnsetpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0526 */ { UD_Ifpatan, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0527 */ { UD_Ifprem, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0528 */ { UD_Ifprem1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0529 */ { UD_Ifptan, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0530 */ { UD_Ifrndint, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0531 */ { UD_Ifrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0532 */ { UD_Ifrstpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0533 */ { UD_Ifnsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0534 */ { UD_Ifscale, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0535 */ { UD_Ifsin, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0536 */ { UD_Ifsincos, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0537 */ { UD_Ifsqrt, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0538 */ { UD_Ifstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0539 */ { UD_Ifstp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0540 */ { UD_Ifstp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0541 */ { UD_Ifstp, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0542 */ { UD_Ifstp, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0543 */ { UD_Ifstp, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0544 */ { UD_Ifstp, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0545 */ { UD_Ifstp, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0546 */ { UD_Ifstp, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0547 */ { UD_Ifstp, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0548 */ { UD_Ifstp, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0549 */ { UD_Ifstp1, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0550 */ { UD_Ifstp1, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0551 */ { UD_Ifstp1, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0552 */ { UD_Ifstp1, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0553 */ { UD_Ifstp1, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0554 */ { UD_Ifstp1, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0555 */ { UD_Ifstp1, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0556 */ { UD_Ifstp1, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0557 */ { UD_Ifstp8, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0558 */ { UD_Ifstp8, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0559 */ { UD_Ifstp8, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0560 */ { UD_Ifstp8, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0561 */ { UD_Ifstp8, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0562 */ { UD_Ifstp8, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0563 */ { UD_Ifstp8, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0564 */ { UD_Ifstp8, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0565 */ { UD_Ifstp9, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0566 */ { UD_Ifstp9, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0567 */ { UD_Ifstp9, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0568 */ { UD_Ifstp9, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0569 */ { UD_Ifstp9, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0570 */ { UD_Ifstp9, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0571 */ { UD_Ifstp9, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0572 */ { UD_Ifstp9, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0573 */ { UD_Ifst, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0574 */ { UD_Ifst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0575 */ { UD_Ifst, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0576 */ { UD_Ifst, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0577 */ { UD_Ifst, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0578 */ { UD_Ifst, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0579 */ { UD_Ifst, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0580 */ { UD_Ifst, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0581 */ { UD_Ifst, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0582 */ { UD_Ifst, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0583 */ { UD_Ifnstcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0584 */ { UD_Ifnstenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0585 */ { UD_Ifnstsw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0586 */ { UD_Ifnstsw, O_AX, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0587 */ { UD_Ifsub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0588 */ { UD_Ifsub, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0589 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0590 */ { UD_Ifsub, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0591 */ { UD_Ifsub, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0592 */ { UD_Ifsub, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0593 */ { UD_Ifsub, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0594 */ { UD_Ifsub, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0595 */ { UD_Ifsub, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0596 */ { UD_Ifsub, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0597 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0598 */ { UD_Ifsub, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0599 */ { UD_Ifsub, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0600 */ { UD_Ifsub, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0601 */ { UD_Ifsub, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0602 */ { UD_Ifsub, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0603 */ { UD_Ifsub, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0604 */ { UD_Ifsub, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0605 */ { UD_Ifsubp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0606 */ { UD_Ifsubp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0607 */ { UD_Ifsubp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0608 */ { UD_Ifsubp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0609 */ { UD_Ifsubp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0610 */ { UD_Ifsubp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0611 */ { UD_Ifsubp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0612 */ { UD_Ifsubp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0613 */ { UD_Ifsubr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0614 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0615 */ { UD_Ifsubr, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0616 */ { UD_Ifsubr, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0617 */ { UD_Ifsubr, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0618 */ { UD_Ifsubr, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0619 */ { UD_Ifsubr, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0620 */ { UD_Ifsubr, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0621 */ { UD_Ifsubr, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0622 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0623 */ { UD_Ifsubr, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0624 */ { UD_Ifsubr, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0625 */ { UD_Ifsubr, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0626 */ { UD_Ifsubr, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0627 */ { UD_Ifsubr, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0628 */ { UD_Ifsubr, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0629 */ { UD_Ifsubr, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0630 */ { UD_Ifsubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0631 */ { UD_Ifsubrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0632 */ { UD_Ifsubrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0633 */ { UD_Ifsubrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0634 */ { UD_Ifsubrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0635 */ { UD_Ifsubrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0636 */ { UD_Ifsubrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0637 */ { UD_Ifsubrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0638 */ { UD_Ifsubrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0639 */ { UD_Iftst, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0640 */ { UD_Ifucom, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0641 */ { UD_Ifucom, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0642 */ { UD_Ifucom, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0643 */ { UD_Ifucom, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0644 */ { UD_Ifucom, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0645 */ { UD_Ifucom, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0646 */ { UD_Ifucom, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0647 */ { UD_Ifucom, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0648 */ { UD_Ifucomp, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0649 */ { UD_Ifucomp, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0650 */ { UD_Ifucomp, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0651 */ { UD_Ifucomp, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0652 */ { UD_Ifucomp, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0653 */ { UD_Ifucomp, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0654 */ { UD_Ifucomp, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0655 */ { UD_Ifucomp, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0656 */ { UD_Ifucompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0657 */ { UD_Ifxam, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0658 */ { UD_Ifxch, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0659 */ { UD_Ifxch, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0660 */ { UD_Ifxch, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0661 */ { UD_Ifxch, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0662 */ { UD_Ifxch, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0663 */ { UD_Ifxch, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0664 */ { UD_Ifxch, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0665 */ { UD_Ifxch, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0666 */ { UD_Ifxch4, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0667 */ { UD_Ifxch4, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0668 */ { UD_Ifxch4, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0669 */ { UD_Ifxch4, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0670 */ { UD_Ifxch4, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0671 */ { UD_Ifxch4, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0672 */ { UD_Ifxch4, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0673 */ { UD_Ifxch4, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0674 */ { UD_Ifxch7, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0675 */ { UD_Ifxch7, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0676 */ { UD_Ifxch7, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0677 */ { UD_Ifxch7, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0678 */ { UD_Ifxch7, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0679 */ { UD_Ifxch7, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0680 */ { UD_Ifxch7, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0681 */ { UD_Ifxch7, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0682 */ { UD_Ifxrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0683 */ { UD_Ifxsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0684 */ { UD_Ifxtract, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0685 */ { UD_Ifyl2x, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0686 */ { UD_Ifyl2xp1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0687 */ { UD_Ihlt, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0688 */ { UD_Iidiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0689 */ { UD_Iidiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0690 */ { UD_Iin, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0691 */ { UD_Iin, O_eAX, O_Ib, O_NONE, O_NONE, P_oso },
+ /* 0692 */ { UD_Iin, O_AL, O_DX, O_NONE, O_NONE, P_none },
+ /* 0693 */ { UD_Iin, O_eAX, O_DX, O_NONE, O_NONE, P_oso },
+ /* 0694 */ { UD_Iimul, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0695 */ { UD_Iimul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0696 */ { UD_Iimul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0697 */ { UD_Iimul, O_Gv, O_Ev, O_Iz, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0698 */ { UD_Iimul, O_Gv, O_Ev, O_sIb, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0699 */ { UD_Iinc, O_R0z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0700 */ { UD_Iinc, O_R1z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0701 */ { UD_Iinc, O_R2z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0702 */ { UD_Iinc, O_R3z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0703 */ { UD_Iinc, O_R4z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0704 */ { UD_Iinc, O_R5z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0705 */ { UD_Iinc, O_R6z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0706 */ { UD_Iinc, O_R7z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0707 */ { UD_Iinc, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0708 */ { UD_Iinc, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0709 */ { UD_Iinsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0710 */ { UD_Iinsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0711 */ { UD_Iinsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0712 */ { UD_Iint1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0713 */ { UD_Iint3, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0714 */ { UD_Iint, O_Ib, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0715 */ { UD_Iinto, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 0716 */ { UD_Iinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0717 */ { UD_Iinvept, O_Gd, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0718 */ { UD_Iinvept, O_Gq, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0719 */ { UD_Iinvlpg, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0720 */ { UD_Iinvlpga, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0721 */ { UD_Iinvvpid, O_Gd, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0722 */ { UD_Iinvvpid, O_Gq, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0723 */ { UD_Iiretw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0724 */ { UD_Iiretd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0725 */ { UD_Iiretq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0726 */ { UD_Ijo, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0727 */ { UD_Ijo, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0728 */ { UD_Ijno, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0729 */ { UD_Ijno, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0730 */ { UD_Ijb, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0731 */ { UD_Ijb, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0732 */ { UD_Ijae, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0733 */ { UD_Ijae, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0734 */ { UD_Ijz, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0735 */ { UD_Ijz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0736 */ { UD_Ijnz, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0737 */ { UD_Ijnz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0738 */ { UD_Ijbe, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0739 */ { UD_Ijbe, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0740 */ { UD_Ija, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0741 */ { UD_Ija, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0742 */ { UD_Ijs, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0743 */ { UD_Ijs, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0744 */ { UD_Ijns, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0745 */ { UD_Ijns, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0746 */ { UD_Ijp, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0747 */ { UD_Ijp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0748 */ { UD_Ijnp, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0749 */ { UD_Ijnp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0750 */ { UD_Ijl, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0751 */ { UD_Ijl, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0752 */ { UD_Ijge, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0753 */ { UD_Ijge, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0754 */ { UD_Ijle, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0755 */ { UD_Ijle, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0756 */ { UD_Ijg, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0757 */ { UD_Ijg, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0758 */ { UD_Ijcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso },
+ /* 0759 */ { UD_Ijecxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso },
+ /* 0760 */ { UD_Ijrcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso },
+ /* 0761 */ { UD_Ijmp, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 0762 */ { UD_Ijmp, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0763 */ { UD_Ijmp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0764 */ { UD_Ijmp, O_Av, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0765 */ { UD_Ijmp, O_Jb, O_NONE, O_NONE, O_NONE, P_def64 },
+ /* 0766 */ { UD_Ilahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0767 */ { UD_Ilar, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0768 */ { UD_Ildmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0769 */ { UD_Ilds, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso },
+ /* 0770 */ { UD_Ilea, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0771 */ { UD_Iles, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso },
+ /* 0772 */ { UD_Ilfs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0773 */ { UD_Ilgs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0774 */ { UD_Ilidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0775 */ { UD_Ilss, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0776 */ { UD_Ileave, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0777 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0778 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0779 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0780 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0781 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0782 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0783 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0784 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0785 */ { UD_Ilgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0786 */ { UD_Illdt, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0787 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0788 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0789 */ { UD_Ilock, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0790 */ { UD_Ilodsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0791 */ { UD_Ilodsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0792 */ { UD_Ilodsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0793 */ { UD_Ilodsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0794 */ { UD_Iloopne, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0795 */ { UD_Iloope, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0796 */ { UD_Iloop, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0797 */ { UD_Ilsl, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0798 */ { UD_Iltr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0799 */ { UD_Imaskmovq, O_P, O_N, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0800 */ { UD_Imaxpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0801 */ { UD_Ivmaxpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0802 */ { UD_Imaxps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0803 */ { UD_Ivmaxps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0804 */ { UD_Imaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0805 */ { UD_Ivmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0806 */ { UD_Imaxss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0807 */ { UD_Ivmaxss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0808 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0809 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0810 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0811 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0812 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0813 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0814 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0815 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0816 */ { UD_Iminpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0817 */ { UD_Ivminpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0818 */ { UD_Iminps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0819 */ { UD_Ivminps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0820 */ { UD_Iminsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0821 */ { UD_Ivminsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0822 */ { UD_Iminss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0823 */ { UD_Ivminss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0824 */ { UD_Imonitor, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0825 */ { UD_Imontmul, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0826 */ { UD_Imov, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0827 */ { UD_Imov, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0828 */ { UD_Imov, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0829 */ { UD_Imov, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0830 */ { UD_Imov, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0831 */ { UD_Imov, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0832 */ { UD_Imov, O_MwRv, O_S, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0833 */ { UD_Imov, O_S, O_MwRv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0834 */ { UD_Imov, O_AL, O_Ob, O_NONE, O_NONE, P_none },
+ /* 0835 */ { UD_Imov, O_rAX, O_Ov, O_NONE, O_NONE, P_aso|P_oso|P_rexw },
+ /* 0836 */ { UD_Imov, O_Ob, O_AL, O_NONE, O_NONE, P_none },
+ /* 0837 */ { UD_Imov, O_Ov, O_rAX, O_NONE, O_NONE, P_aso|P_oso|P_rexw },
+ /* 0838 */ { UD_Imov, O_R0b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0839 */ { UD_Imov, O_R1b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0840 */ { UD_Imov, O_R2b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0841 */ { UD_Imov, O_R3b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0842 */ { UD_Imov, O_R4b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0843 */ { UD_Imov, O_R5b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0844 */ { UD_Imov, O_R6b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0845 */ { UD_Imov, O_R7b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0846 */ { UD_Imov, O_R0v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0847 */ { UD_Imov, O_R1v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0848 */ { UD_Imov, O_R2v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0849 */ { UD_Imov, O_R3v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0850 */ { UD_Imov, O_R4v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0851 */ { UD_Imov, O_R5v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0852 */ { UD_Imov, O_R6v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0853 */ { UD_Imov, O_R7v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0854 */ { UD_Imov, O_R, O_C, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0855 */ { UD_Imov, O_R, O_D, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0856 */ { UD_Imov, O_C, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0857 */ { UD_Imov, O_D, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0858 */ { UD_Imovapd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0859 */ { UD_Ivmovapd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0860 */ { UD_Imovapd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0861 */ { UD_Ivmovapd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0862 */ { UD_Imovaps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0863 */ { UD_Ivmovaps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0864 */ { UD_Imovaps, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0865 */ { UD_Ivmovaps, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0866 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0867 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0868 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0869 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0870 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0871 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0872 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0873 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0874 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0875 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0876 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0877 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0878 */ { UD_Imovhpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0879 */ { UD_Ivmovhpd, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0880 */ { UD_Imovhpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0881 */ { UD_Ivmovhpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0882 */ { UD_Imovhps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0883 */ { UD_Ivmovhps, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0884 */ { UD_Imovhps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0885 */ { UD_Ivmovhps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0886 */ { UD_Imovlhps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0887 */ { UD_Ivmovlhps, O_Vx, O_Hx, O_Ux, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0888 */ { UD_Imovlpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0889 */ { UD_Ivmovlpd, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0890 */ { UD_Imovlpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0891 */ { UD_Ivmovlpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0892 */ { UD_Imovlps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0893 */ { UD_Ivmovlps, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0894 */ { UD_Imovlps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0895 */ { UD_Ivmovlps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0896 */ { UD_Imovhlps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0897 */ { UD_Ivmovhlps, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0898 */ { UD_Imovmskpd, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb },
+ /* 0899 */ { UD_Ivmovmskpd, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb|P_vexl },
+ /* 0900 */ { UD_Imovmskps, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb },
+ /* 0901 */ { UD_Ivmovmskps, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb },
+ /* 0902 */ { UD_Imovntdq, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0903 */ { UD_Ivmovntdq, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0904 */ { UD_Imovnti, O_M, O_Gy, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0905 */ { UD_Imovntpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0906 */ { UD_Ivmovntpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0907 */ { UD_Imovntps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0908 */ { UD_Ivmovntps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0909 */ { UD_Imovntq, O_M, O_P, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0910 */ { UD_Imovq, O_P, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0911 */ { UD_Imovq, O_V, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0912 */ { UD_Ivmovq, O_Vx, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0913 */ { UD_Imovq, O_Eq, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0914 */ { UD_Imovq, O_Eq, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0915 */ { UD_Ivmovq, O_Eq, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0916 */ { UD_Imovq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0917 */ { UD_Ivmovq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0918 */ { UD_Imovq, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0919 */ { UD_Ivmovq, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0920 */ { UD_Imovq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0921 */ { UD_Imovq, O_Q, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0922 */ { UD_Imovsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0923 */ { UD_Imovsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0924 */ { UD_Imovsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0925 */ { UD_Imovsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0926 */ { UD_Imovsd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0927 */ { UD_Imovsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0928 */ { UD_Imovss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0929 */ { UD_Imovss, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0930 */ { UD_Imovsx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0931 */ { UD_Imovsx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0932 */ { UD_Imovupd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0933 */ { UD_Ivmovupd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0934 */ { UD_Imovupd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0935 */ { UD_Ivmovupd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0936 */ { UD_Imovups, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0937 */ { UD_Ivmovups, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0938 */ { UD_Imovups, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0939 */ { UD_Ivmovups, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0940 */ { UD_Imovzx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0941 */ { UD_Imovzx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0942 */ { UD_Imul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0943 */ { UD_Imul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0944 */ { UD_Imulpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0945 */ { UD_Ivmulpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0946 */ { UD_Imulps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0947 */ { UD_Ivmulps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0948 */ { UD_Imulsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0949 */ { UD_Ivmulsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0950 */ { UD_Imulss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0951 */ { UD_Ivmulss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0952 */ { UD_Imwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0953 */ { UD_Ineg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0954 */ { UD_Ineg, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0955 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0956 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0957 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0958 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0959 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0960 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0961 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0962 */ { UD_Inot, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0963 */ { UD_Inot, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0964 */ { UD_Ior, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0965 */ { UD_Ior, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0966 */ { UD_Ior, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0967 */ { UD_Ior, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0968 */ { UD_Ior, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0969 */ { UD_Ior, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0970 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0971 */ { UD_Ior, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0972 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0973 */ { UD_Ior, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0974 */ { UD_Iorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0975 */ { UD_Ivorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0976 */ { UD_Iorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0977 */ { UD_Ivorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0978 */ { UD_Iout, O_Ib, O_AL, O_NONE, O_NONE, P_none },
+ /* 0979 */ { UD_Iout, O_Ib, O_eAX, O_NONE, O_NONE, P_oso },
+ /* 0980 */ { UD_Iout, O_DX, O_AL, O_NONE, O_NONE, P_none },
+ /* 0981 */ { UD_Iout, O_DX, O_eAX, O_NONE, O_NONE, P_oso },
+ /* 0982 */ { UD_Ioutsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0983 */ { UD_Ioutsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0984 */ { UD_Ioutsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0985 */ { UD_Ipacksswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0986 */ { UD_Ivpacksswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0987 */ { UD_Ipacksswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0988 */ { UD_Ipackssdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0989 */ { UD_Ivpackssdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0990 */ { UD_Ipackssdw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0991 */ { UD_Ipackuswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0992 */ { UD_Ivpackuswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0993 */ { UD_Ipackuswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0994 */ { UD_Ipaddb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0995 */ { UD_Ivpaddb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0996 */ { UD_Ipaddb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0997 */ { UD_Ipaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0998 */ { UD_Ipaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0999 */ { UD_Ivpaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1000 */ { UD_Ipaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1001 */ { UD_Ipaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1002 */ { UD_Ivpaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1003 */ { UD_Ipaddsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1004 */ { UD_Ipaddsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1005 */ { UD_Ivpaddsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1006 */ { UD_Ipaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1007 */ { UD_Ipaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1008 */ { UD_Ivpaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1009 */ { UD_Ipaddusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1010 */ { UD_Ipaddusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1011 */ { UD_Ivpaddusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1012 */ { UD_Ipaddusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1013 */ { UD_Ipaddusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1014 */ { UD_Ivpaddusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1015 */ { UD_Ipand, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1016 */ { UD_Ivpand, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1017 */ { UD_Ipand, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1018 */ { UD_Ipandn, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1019 */ { UD_Ivpandn, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1020 */ { UD_Ipandn, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1021 */ { UD_Ipavgb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1022 */ { UD_Ivpavgb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1023 */ { UD_Ipavgb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1024 */ { UD_Ipavgw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1025 */ { UD_Ivpavgw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1026 */ { UD_Ipavgw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1027 */ { UD_Ipcmpeqb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1028 */ { UD_Ipcmpeqb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1029 */ { UD_Ivpcmpeqb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1030 */ { UD_Ipcmpeqw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1031 */ { UD_Ipcmpeqw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1032 */ { UD_Ivpcmpeqw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1033 */ { UD_Ipcmpeqd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1034 */ { UD_Ipcmpeqd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1035 */ { UD_Ivpcmpeqd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1036 */ { UD_Ipcmpgtb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1037 */ { UD_Ivpcmpgtb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1038 */ { UD_Ipcmpgtb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1039 */ { UD_Ipcmpgtw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1040 */ { UD_Ivpcmpgtw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1041 */ { UD_Ipcmpgtw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1042 */ { UD_Ipcmpgtd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1043 */ { UD_Ivpcmpgtd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1044 */ { UD_Ipcmpgtd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1045 */ { UD_Ipextrb, O_MbRv, O_V, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 },
+ /* 1046 */ { UD_Ivpextrb, O_MbRv, O_Vx, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 },
+ /* 1047 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1048 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1049 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1050 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1051 */ { UD_Ipextrq, O_Eq, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 },
+ /* 1052 */ { UD_Ivpextrq, O_Eq, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 },
+ /* 1053 */ { UD_Ipextrw, O_Gd, O_U, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb },
+ /* 1054 */ { UD_Ivpextrw, O_Gd, O_Ux, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb },
+ /* 1055 */ { UD_Ipextrw, O_Gd, O_N, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1056 */ { UD_Ipextrw, O_MwRd, O_V, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb },
+ /* 1057 */ { UD_Ivpextrw, O_MwRd, O_Vx, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb },
+ /* 1058 */ { UD_Ipinsrb, O_V, O_MbRd, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1059 */ { UD_Ipinsrw, O_P, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1060 */ { UD_Ipinsrw, O_V, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1061 */ { UD_Ivpinsrw, O_Vx, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1062 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1063 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1064 */ { UD_Ipinsrq, O_V, O_Eq, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1065 */ { UD_Ivpinsrb, O_V, O_H, O_MbRd, O_Ib, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1066 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1067 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1068 */ { UD_Ivpinsrq, O_V, O_H, O_Eq, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1069 */ { UD_Ipmaddwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1070 */ { UD_Ipmaddwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1071 */ { UD_Ivpmaddwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1072 */ { UD_Ipmaxsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1073 */ { UD_Ivpmaxsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1074 */ { UD_Ipmaxsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1075 */ { UD_Ipmaxub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1076 */ { UD_Ipmaxub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1077 */ { UD_Ivpmaxub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1078 */ { UD_Ipminsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1079 */ { UD_Ivpminsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1080 */ { UD_Ipminsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1081 */ { UD_Ipminub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1082 */ { UD_Ivpminub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1083 */ { UD_Ipminub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1084 */ { UD_Ipmovmskb, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb },
+ /* 1085 */ { UD_Ivpmovmskb, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb },
+ /* 1086 */ { UD_Ipmovmskb, O_Gd, O_N, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb },
+ /* 1087 */ { UD_Ipmulhuw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1088 */ { UD_Ipmulhuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1089 */ { UD_Ivpmulhuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1090 */ { UD_Ipmulhw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1091 */ { UD_Ivpmulhw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1092 */ { UD_Ipmulhw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1093 */ { UD_Ipmullw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1094 */ { UD_Ipmullw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1095 */ { UD_Ivpmullw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1096 */ { UD_Ipop, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1097 */ { UD_Ipop, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1098 */ { UD_Ipop, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1099 */ { UD_Ipop, O_GS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1100 */ { UD_Ipop, O_FS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1101 */ { UD_Ipop, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1102 */ { UD_Ipop, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1103 */ { UD_Ipop, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1104 */ { UD_Ipop, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1105 */ { UD_Ipop, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1106 */ { UD_Ipop, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1107 */ { UD_Ipop, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1108 */ { UD_Ipop, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1109 */ { UD_Ipop, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1110 */ { UD_Ipopa, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1111 */ { UD_Ipopad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1112 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1113 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1114 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1115 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1116 */ { UD_Ipor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1117 */ { UD_Ivpor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1118 */ { UD_Ipor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1119 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1120 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1121 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1122 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1123 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1124 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1125 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1126 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1127 */ { UD_Iprefetchnta, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1128 */ { UD_Iprefetcht0, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1129 */ { UD_Iprefetcht1, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1130 */ { UD_Iprefetcht2, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1131 */ { UD_Ipsadbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1132 */ { UD_Ivpsadbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1133 */ { UD_Ipsadbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1134 */ { UD_Ipshufw, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1135 */ { UD_Ipsllw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1136 */ { UD_Ipsllw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1137 */ { UD_Ipsllw, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1138 */ { UD_Ipsllw, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1139 */ { UD_Ipslld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1140 */ { UD_Ipslld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1141 */ { UD_Ipslld, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1142 */ { UD_Ipslld, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1143 */ { UD_Ipsllq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1144 */ { UD_Ipsllq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1145 */ { UD_Ipsllq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1146 */ { UD_Ipsllq, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1147 */ { UD_Ipsraw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1148 */ { UD_Ipsraw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1149 */ { UD_Ivpsraw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1150 */ { UD_Ipsraw, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1151 */ { UD_Ivpsraw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1152 */ { UD_Ipsraw, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1153 */ { UD_Ipsrad, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1154 */ { UD_Ipsrad, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1155 */ { UD_Ivpsrad, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1156 */ { UD_Ipsrad, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1157 */ { UD_Ipsrad, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1158 */ { UD_Ivpsrad, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1159 */ { UD_Ipsrlw, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1160 */ { UD_Ipsrlw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1161 */ { UD_Ipsrlw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1162 */ { UD_Ivpsrlw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1163 */ { UD_Ipsrlw, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1164 */ { UD_Ivpsrlw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1165 */ { UD_Ipsrld, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1166 */ { UD_Ipsrld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1167 */ { UD_Ipsrld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1168 */ { UD_Ivpsrld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1169 */ { UD_Ipsrld, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1170 */ { UD_Ivpsrld, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1171 */ { UD_Ipsrlq, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1172 */ { UD_Ipsrlq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1173 */ { UD_Ipsrlq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1174 */ { UD_Ivpsrlq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1175 */ { UD_Ipsrlq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1176 */ { UD_Ivpsrlq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1177 */ { UD_Ipsubb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1178 */ { UD_Ivpsubb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1179 */ { UD_Ipsubb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1180 */ { UD_Ipsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1181 */ { UD_Ivpsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1182 */ { UD_Ipsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1183 */ { UD_Ipsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1184 */ { UD_Ipsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1185 */ { UD_Ivpsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1186 */ { UD_Ipsubsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1187 */ { UD_Ipsubsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1188 */ { UD_Ivpsubsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1189 */ { UD_Ipsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1190 */ { UD_Ipsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1191 */ { UD_Ivpsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1192 */ { UD_Ipsubusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1193 */ { UD_Ipsubusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1194 */ { UD_Ivpsubusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1195 */ { UD_Ipsubusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1196 */ { UD_Ipsubusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1197 */ { UD_Ivpsubusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1198 */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1199 */ { UD_Ivpunpckhbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1200 */ { UD_Ipunpckhbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1201 */ { UD_Ipunpckhwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1202 */ { UD_Ivpunpckhwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1203 */ { UD_Ipunpckhwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1204 */ { UD_Ipunpckhdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1205 */ { UD_Ivpunpckhdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1206 */ { UD_Ipunpckhdq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1207 */ { UD_Ipunpcklbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1208 */ { UD_Ivpunpcklbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1209 */ { UD_Ipunpcklbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1210 */ { UD_Ipunpcklwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1211 */ { UD_Ivpunpcklwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1212 */ { UD_Ipunpcklwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1213 */ { UD_Ipunpckldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1214 */ { UD_Ivpunpckldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1215 */ { UD_Ipunpckldq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1216 */ { UD_Ipi2fw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1217 */ { UD_Ipi2fd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1218 */ { UD_Ipf2iw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1219 */ { UD_Ipf2id, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1220 */ { UD_Ipfnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1221 */ { UD_Ipfpnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1222 */ { UD_Ipfcmpge, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1223 */ { UD_Ipfmin, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1224 */ { UD_Ipfrcp, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1225 */ { UD_Ipfrsqrt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1226 */ { UD_Ipfsub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1227 */ { UD_Ipfadd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1228 */ { UD_Ipfcmpgt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1229 */ { UD_Ipfmax, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1230 */ { UD_Ipfrcpit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1231 */ { UD_Ipfrsqit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1232 */ { UD_Ipfsubr, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1233 */ { UD_Ipfacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1234 */ { UD_Ipfcmpeq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1235 */ { UD_Ipfmul, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1236 */ { UD_Ipfrcpit2, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1237 */ { UD_Ipmulhrw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1238 */ { UD_Ipswapd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1239 */ { UD_Ipavgusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1240 */ { UD_Ipush, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1241 */ { UD_Ipush, O_CS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1242 */ { UD_Ipush, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1243 */ { UD_Ipush, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1244 */ { UD_Ipush, O_GS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1245 */ { UD_Ipush, O_FS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1246 */ { UD_Ipush, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1247 */ { UD_Ipush, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1248 */ { UD_Ipush, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1249 */ { UD_Ipush, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1250 */ { UD_Ipush, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1251 */ { UD_Ipush, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1252 */ { UD_Ipush, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1253 */ { UD_Ipush, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1254 */ { UD_Ipush, O_sIz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1255 */ { UD_Ipush, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1256 */ { UD_Ipush, O_sIb, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1257 */ { UD_Ipusha, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1258 */ { UD_Ipushad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1259 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1260 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 },
+ /* 1261 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1262 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 },
+ /* 1263 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 },
+ /* 1264 */ { UD_Ipxor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1265 */ { UD_Ivpxor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1266 */ { UD_Ipxor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1267 */ { UD_Ircl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1268 */ { UD_Ircl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1269 */ { UD_Ircl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1270 */ { UD_Ircl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1271 */ { UD_Ircl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1272 */ { UD_Ircl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1273 */ { UD_Ircr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1274 */ { UD_Ircr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1275 */ { UD_Ircr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1276 */ { UD_Ircr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1277 */ { UD_Ircr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1278 */ { UD_Ircr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1279 */ { UD_Irol, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1280 */ { UD_Irol, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1281 */ { UD_Irol, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1282 */ { UD_Irol, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1283 */ { UD_Irol, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1284 */ { UD_Irol, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1285 */ { UD_Iror, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1286 */ { UD_Iror, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1287 */ { UD_Iror, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1288 */ { UD_Iror, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1289 */ { UD_Iror, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1290 */ { UD_Iror, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1291 */ { UD_Ircpps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1292 */ { UD_Ivrcpps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1293 */ { UD_Ircpss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1294 */ { UD_Ivrcpss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1295 */ { UD_Irdmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1296 */ { UD_Irdpmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1297 */ { UD_Irdtsc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1298 */ { UD_Irdtscp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1299 */ { UD_Irepne, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1300 */ { UD_Irep, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1301 */ { UD_Iret, O_Iw, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1302 */ { UD_Iret, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1303 */ { UD_Iretf, O_Iw, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1304 */ { UD_Iretf, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1305 */ { UD_Irsm, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1306 */ { UD_Irsqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1307 */ { UD_Ivrsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1308 */ { UD_Irsqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1309 */ { UD_Ivrsqrtss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1310 */ { UD_Isahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1311 */ { UD_Isalc, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1312 */ { UD_Isar, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1313 */ { UD_Isar, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1314 */ { UD_Isar, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1315 */ { UD_Isar, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1316 */ { UD_Isar, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1317 */ { UD_Isar, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1318 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1319 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1320 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1321 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1322 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1323 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1324 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1325 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1326 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1327 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1328 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1329 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1330 */ { UD_Ishr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1331 */ { UD_Ishr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1332 */ { UD_Ishr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1333 */ { UD_Ishr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1334 */ { UD_Ishr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1335 */ { UD_Ishr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1336 */ { UD_Isbb, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1337 */ { UD_Isbb, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1338 */ { UD_Isbb, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1339 */ { UD_Isbb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1340 */ { UD_Isbb, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1341 */ { UD_Isbb, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1342 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1343 */ { UD_Isbb, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1344 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 1345 */ { UD_Isbb, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1346 */ { UD_Iscasb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz },
+ /* 1347 */ { UD_Iscasw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw },
+ /* 1348 */ { UD_Iscasd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw },
+ /* 1349 */ { UD_Iscasq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw },
+ /* 1350 */ { UD_Iseto, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1351 */ { UD_Isetno, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1352 */ { UD_Isetb, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1353 */ { UD_Isetae, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1354 */ { UD_Isetz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1355 */ { UD_Isetnz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1356 */ { UD_Isetbe, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1357 */ { UD_Iseta, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1358 */ { UD_Isets, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1359 */ { UD_Isetns, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1360 */ { UD_Isetp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1361 */ { UD_Isetnp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1362 */ { UD_Isetl, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1363 */ { UD_Isetge, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1364 */ { UD_Isetle, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1365 */ { UD_Isetg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1366 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1367 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1368 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1369 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1370 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1371 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1372 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1373 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1374 */ { UD_Isgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1375 */ { UD_Ishld, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1376 */ { UD_Ishld, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1377 */ { UD_Ishrd, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1378 */ { UD_Ishrd, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1379 */ { UD_Ishufpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1380 */ { UD_Ivshufpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1381 */ { UD_Ishufps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1382 */ { UD_Ivshufps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1383 */ { UD_Isidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1384 */ { UD_Isldt, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1385 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1386 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1387 */ { UD_Isqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1388 */ { UD_Ivsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1389 */ { UD_Isqrtpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1390 */ { UD_Ivsqrtpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1391 */ { UD_Isqrtsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1392 */ { UD_Ivsqrtsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1393 */ { UD_Isqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1394 */ { UD_Ivsqrtss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1395 */ { UD_Istc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1396 */ { UD_Istd, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1397 */ { UD_Istgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1398 */ { UD_Isti, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1399 */ { UD_Iskinit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1400 */ { UD_Istmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1401 */ { UD_Ivstmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1402 */ { UD_Istosb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 1403 */ { UD_Istosw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 1404 */ { UD_Istosd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 1405 */ { UD_Istosq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 1406 */ { UD_Istr, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1407 */ { UD_Isub, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1408 */ { UD_Isub, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1409 */ { UD_Isub, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1410 */ { UD_Isub, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1411 */ { UD_Isub, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1412 */ { UD_Isub, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1413 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1414 */ { UD_Isub, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1415 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 1416 */ { UD_Isub, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1417 */ { UD_Isubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1418 */ { UD_Ivsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1419 */ { UD_Isubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1420 */ { UD_Ivsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1421 */ { UD_Isubsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1422 */ { UD_Ivsubsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1423 */ { UD_Isubss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1424 */ { UD_Ivsubss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1425 */ { UD_Iswapgs, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1426 */ { UD_Isyscall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1427 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1428 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1429 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1430 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1431 */ { UD_Isysret, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1432 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1433 */ { UD_Itest, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1434 */ { UD_Itest, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1435 */ { UD_Itest, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1436 */ { UD_Itest, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1437 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1438 */ { UD_Itest, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1439 */ { UD_Itest, O_Ev, O_Iz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1440 */ { UD_Iucomisd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1441 */ { UD_Ivucomisd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1442 */ { UD_Iucomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1443 */ { UD_Ivucomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1444 */ { UD_Iud2, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1445 */ { UD_Iunpckhpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1446 */ { UD_Ivunpckhpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1447 */ { UD_Iunpckhps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1448 */ { UD_Ivunpckhps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1449 */ { UD_Iunpcklps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1450 */ { UD_Ivunpcklps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1451 */ { UD_Iunpcklpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1452 */ { UD_Ivunpcklpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1453 */ { UD_Iverr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1454 */ { UD_Iverw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1455 */ { UD_Ivmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1456 */ { UD_Irdrand, O_R, O_NONE, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1457 */ { UD_Ivmclear, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1458 */ { UD_Ivmxon, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1459 */ { UD_Ivmptrld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1460 */ { UD_Ivmptrst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1461 */ { UD_Ivmlaunch, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1462 */ { UD_Ivmresume, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1463 */ { UD_Ivmxoff, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1464 */ { UD_Ivmread, O_Ey, O_Gy, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1465 */ { UD_Ivmwrite, O_Gy, O_Ey, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1466 */ { UD_Ivmrun, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1467 */ { UD_Ivmmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1468 */ { UD_Ivmload, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1469 */ { UD_Ivmsave, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1470 */ { UD_Iwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1471 */ { UD_Iwbinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1472 */ { UD_Iwrmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1473 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb },
+ /* 1474 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1475 */ { UD_Ixchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1476 */ { UD_Ixchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1477 */ { UD_Ixchg, O_R0v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1478 */ { UD_Ixchg, O_R1v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1479 */ { UD_Ixchg, O_R2v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1480 */ { UD_Ixchg, O_R3v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1481 */ { UD_Ixchg, O_R4v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1482 */ { UD_Ixchg, O_R5v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1483 */ { UD_Ixchg, O_R6v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1484 */ { UD_Ixchg, O_R7v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1485 */ { UD_Ixgetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1486 */ { UD_Ixlatb, O_NONE, O_NONE, O_NONE, O_NONE, P_rexw|P_seg },
+ /* 1487 */ { UD_Ixor, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1488 */ { UD_Ixor, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1489 */ { UD_Ixor, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1490 */ { UD_Ixor, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1491 */ { UD_Ixor, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1492 */ { UD_Ixor, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1493 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1494 */ { UD_Ixor, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1495 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 1496 */ { UD_Ixor, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1497 */ { UD_Ixorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1498 */ { UD_Ivxorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1499 */ { UD_Ixorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1500 */ { UD_Ivxorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1501 */ { UD_Ixcryptecb, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1502 */ { UD_Ixcryptcbc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1503 */ { UD_Ixcryptctr, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1504 */ { UD_Ixcryptcfb, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1505 */ { UD_Ixcryptofb, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1506 */ { UD_Ixrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1507 */ { UD_Ixsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1508 */ { UD_Ixsetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1509 */ { UD_Ixsha1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1510 */ { UD_Ixsha256, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1511 */ { UD_Ixstore, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1512 */ { UD_Ipclmulqdq, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1513 */ { UD_Ivpclmulqdq, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1514 */ { UD_Igetsec, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1515 */ { UD_Imovdqa, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1516 */ { UD_Ivmovdqa, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1517 */ { UD_Imovdqa, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1518 */ { UD_Ivmovdqa, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1519 */ { UD_Imaskmovdqu, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1520 */ { UD_Ivmaskmovdqu, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1521 */ { UD_Imovdq2q, O_P, O_U, O_NONE, O_NONE, P_aso|P_rexb },
+ /* 1522 */ { UD_Imovdqu, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1523 */ { UD_Ivmovdqu, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1524 */ { UD_Imovdqu, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1525 */ { UD_Ivmovdqu, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1526 */ { UD_Imovq2dq, O_V, O_N, O_NONE, O_NONE, P_aso|P_rexr },
+ /* 1527 */ { UD_Ipaddq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1528 */ { UD_Ipaddq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1529 */ { UD_Ivpaddq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1530 */ { UD_Ipsubq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1531 */ { UD_Ivpsubq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1532 */ { UD_Ipsubq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1533 */ { UD_Ipmuludq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1534 */ { UD_Ipmuludq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1535 */ { UD_Ipshufhw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1536 */ { UD_Ivpshufhw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1537 */ { UD_Ipshuflw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1538 */ { UD_Ivpshuflw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1539 */ { UD_Ipshufd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1540 */ { UD_Ivpshufd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1541 */ { UD_Ipslldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1542 */ { UD_Ivpslldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1543 */ { UD_Ipsrldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1544 */ { UD_Ivpsrldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1545 */ { UD_Ipunpckhqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1546 */ { UD_Ivpunpckhqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1547 */ { UD_Ipunpcklqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1548 */ { UD_Ivpunpcklqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1549 */ { UD_Ihaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1550 */ { UD_Ivhaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1551 */ { UD_Ihaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1552 */ { UD_Ivhaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1553 */ { UD_Ihsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1554 */ { UD_Ivhsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1555 */ { UD_Ihsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1556 */ { UD_Ivhsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1557 */ { UD_Iinsertps, O_V, O_Md, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1558 */ { UD_Ivinsertps, O_Vx, O_Hx, O_Md, O_Ib, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1559 */ { UD_Ilddqu, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1560 */ { UD_Ivlddqu, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1561 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1562 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1563 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1564 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1565 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1566 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1567 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1568 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1569 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1570 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1571 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1572 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1573 */ { UD_Ipabsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1574 */ { UD_Ipabsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1575 */ { UD_Ivpabsb, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1576 */ { UD_Ipabsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1577 */ { UD_Ipabsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1578 */ { UD_Ivpabsw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1579 */ { UD_Ipabsd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1580 */ { UD_Ipabsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1581 */ { UD_Ivpabsd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1582 */ { UD_Ipshufb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1583 */ { UD_Ipshufb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1584 */ { UD_Ivpshufb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1585 */ { UD_Iphaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1586 */ { UD_Iphaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1587 */ { UD_Ivphaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1588 */ { UD_Iphaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1589 */ { UD_Iphaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1590 */ { UD_Ivphaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1591 */ { UD_Iphaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1592 */ { UD_Iphaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1593 */ { UD_Ivphaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1594 */ { UD_Ipmaddubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1595 */ { UD_Ipmaddubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1596 */ { UD_Ivpmaddubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1597 */ { UD_Iphsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1598 */ { UD_Iphsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1599 */ { UD_Ivphsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1600 */ { UD_Iphsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1601 */ { UD_Iphsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1602 */ { UD_Ivphsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1603 */ { UD_Iphsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1604 */ { UD_Iphsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1605 */ { UD_Ivphsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1606 */ { UD_Ipsignb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1607 */ { UD_Ipsignb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1608 */ { UD_Ivpsignb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1609 */ { UD_Ipsignd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1610 */ { UD_Ipsignd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1611 */ { UD_Ivpsignd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1612 */ { UD_Ipsignw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1613 */ { UD_Ipsignw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1614 */ { UD_Ivpsignw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1615 */ { UD_Ipmulhrsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1616 */ { UD_Ipmulhrsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1617 */ { UD_Ivpmulhrsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1618 */ { UD_Ipalignr, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1619 */ { UD_Ipalignr, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1620 */ { UD_Ivpalignr, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1621 */ { UD_Ipblendvb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1622 */ { UD_Ipmuldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1623 */ { UD_Ivpmuldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1624 */ { UD_Ipminsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1625 */ { UD_Ivpminsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1626 */ { UD_Ipminsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1627 */ { UD_Ivpminsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1628 */ { UD_Ipminuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1629 */ { UD_Ivpminuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1630 */ { UD_Ipminud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1631 */ { UD_Ivpminud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1632 */ { UD_Ipmaxsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1633 */ { UD_Ivpmaxsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1634 */ { UD_Ipmaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1635 */ { UD_Ivpmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1636 */ { UD_Ipmaxud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1637 */ { UD_Ivpmaxud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1638 */ { UD_Ipmaxuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1639 */ { UD_Ivpmaxuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1640 */ { UD_Ipmulld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1641 */ { UD_Ivpmulld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1642 */ { UD_Iphminposuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1643 */ { UD_Ivphminposuw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1644 */ { UD_Iroundps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1645 */ { UD_Ivroundps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1646 */ { UD_Iroundpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1647 */ { UD_Ivroundpd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1648 */ { UD_Iroundss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1649 */ { UD_Ivroundss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1650 */ { UD_Iroundsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1651 */ { UD_Ivroundsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1652 */ { UD_Iblendpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1653 */ { UD_Ivblendpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1654 */ { UD_Iblendps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1655 */ { UD_Ivblendps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1656 */ { UD_Iblendvpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1657 */ { UD_Iblendvps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1658 */ { UD_Ibound, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso },
+ /* 1659 */ { UD_Ibsf, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1660 */ { UD_Ibsr, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1661 */ { UD_Ibswap, O_R0y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1662 */ { UD_Ibswap, O_R1y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1663 */ { UD_Ibswap, O_R2y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1664 */ { UD_Ibswap, O_R3y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1665 */ { UD_Ibswap, O_R4y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1666 */ { UD_Ibswap, O_R5y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1667 */ { UD_Ibswap, O_R6y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1668 */ { UD_Ibswap, O_R7y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1669 */ { UD_Ibt, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1670 */ { UD_Ibt, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1671 */ { UD_Ibtc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1672 */ { UD_Ibtc, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1673 */ { UD_Ibtr, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1674 */ { UD_Ibtr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1675 */ { UD_Ibts, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1676 */ { UD_Ibts, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1677 */ { UD_Ipblendw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1678 */ { UD_Ivpblendw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1679 */ { UD_Impsadbw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1680 */ { UD_Ivmpsadbw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1681 */ { UD_Imovntdqa, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1682 */ { UD_Ivmovntdqa, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl },
+ /* 1683 */ { UD_Ipackusdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1684 */ { UD_Ivpackusdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl },
+ /* 1685 */ { UD_Ipmovsxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1686 */ { UD_Ivpmovsxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1687 */ { UD_Ipmovsxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1688 */ { UD_Ivpmovsxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1689 */ { UD_Ipmovsxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1690 */ { UD_Ivpmovsxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1691 */ { UD_Ipmovsxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1692 */ { UD_Ivpmovsxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1693 */ { UD_Ipmovsxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1694 */ { UD_Ivpmovsxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1695 */ { UD_Ipmovsxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1696 */ { UD_Ipmovzxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1697 */ { UD_Ivpmovzxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1698 */ { UD_Ipmovzxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1699 */ { UD_Ivpmovzxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1700 */ { UD_Ipmovzxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1701 */ { UD_Ivpmovzxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1702 */ { UD_Ipmovzxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1703 */ { UD_Ivpmovzxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1704 */ { UD_Ipmovzxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1705 */ { UD_Ivpmovzxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1706 */ { UD_Ipmovzxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1707 */ { UD_Ivpmovzxdq, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1708 */ { UD_Ipcmpeqq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1709 */ { UD_Ivpcmpeqq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1710 */ { UD_Ipopcnt, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1711 */ { UD_Iptest, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1712 */ { UD_Ivptest, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl },
+ /* 1713 */ { UD_Ipcmpestri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1714 */ { UD_Ivpcmpestri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1715 */ { UD_Ipcmpestrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1716 */ { UD_Ivpcmpestrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1717 */ { UD_Ipcmpgtq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1718 */ { UD_Ivpcmpgtq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1719 */ { UD_Ipcmpistri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1720 */ { UD_Ivpcmpistri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1721 */ { UD_Ipcmpistrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1722 */ { UD_Ivpcmpistrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1723 */ { UD_Imovbe, O_Gv, O_Mv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1724 */ { UD_Imovbe, O_Mv, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1725 */ { UD_Icrc32, O_Gy, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1726 */ { UD_Icrc32, O_Gy, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1727 */ { UD_Ivbroadcastss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1728 */ { UD_Ivbroadcastsd, O_Vqq, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1729 */ { UD_Ivextractf128, O_Wdq, O_Vqq, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1730 */ { UD_Ivinsertf128, O_Vqq, O_Hqq, O_Wdq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1731 */ { UD_Ivmaskmovps, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1732 */ { UD_Ivmaskmovps, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1733 */ { UD_Ivmaskmovpd, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1734 */ { UD_Ivmaskmovpd, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1735 */ { UD_Ivpermilpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1736 */ { UD_Ivpermilpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1737 */ { UD_Ivpermilps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1738 */ { UD_Ivpermilps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1739 */ { UD_Ivperm2f128, O_Vqq, O_Hqq, O_Wqq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1740 */ { UD_Ivtestps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1741 */ { UD_Ivtestpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1742 */ { UD_Ivzeroupper, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1743 */ { UD_Ivzeroall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1744 */ { UD_Ivblendvpd, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1745 */ { UD_Ivblendvps, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1746 */ { UD_Ivmovsd, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1747 */ { UD_Ivmovsd, O_V, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1748 */ { UD_Ivmovsd, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1749 */ { UD_Ivmovsd, O_Mq, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1750 */ { UD_Ivmovss, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1751 */ { UD_Ivmovss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1752 */ { UD_Ivmovss, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1753 */ { UD_Ivmovss, O_Md, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1754 */ { UD_Ivpblendvb, O_V, O_H, O_W, O_L, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1755 */ { UD_Ivpsllw, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1756 */ { UD_Ivpsllw, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1757 */ { UD_Ivpslld, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1758 */ { UD_Ivpslld, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1759 */ { UD_Ivpsllq, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1760 */ { UD_Ivpsllq, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+};
+
+
+const char* ud_mnemonics_str[] = {
+ "aaa",
+ "aad",
+ "aam",
+ "aas",
+ "adc",
+ "add",
+ "addpd",
+ "addps",
+ "addsd",
+ "addss",
+ "addsubpd",
+ "addsubps",
+ "aesdec",
+ "aesdeclast",
+ "aesenc",
+ "aesenclast",
+ "aesimc",
+ "aeskeygenassist",
+ "and",
+ "andnpd",
+ "andnps",
+ "andpd",
+ "andps",
+ "arpl",
+ "blendpd",
+ "blendps",
+ "blendvpd",
+ "blendvps",
+ "bound",
+ "bsf",
+ "bsr",
+ "bswap",
+ "bt",
+ "btc",
+ "btr",
+ "bts",
+ "call",
+ "cbw",
+ "cdq",
+ "cdqe",
+ "clc",
+ "cld",
+ "clflush",
+ "clgi",
+ "cli",
+ "clts",
+ "cmc",
+ "cmova",
+ "cmovae",
+ "cmovb",
+ "cmovbe",
+ "cmovg",
+ "cmovge",
+ "cmovl",
+ "cmovle",
+ "cmovno",
+ "cmovnp",
+ "cmovns",
+ "cmovnz",
+ "cmovo",
+ "cmovp",
+ "cmovs",
+ "cmovz",
+ "cmp",
+ "cmppd",
+ "cmpps",
+ "cmpsb",
+ "cmpsd",
+ "cmpsq",
+ "cmpss",
+ "cmpsw",
+ "cmpxchg",
+ "cmpxchg16b",
+ "cmpxchg8b",
+ "comisd",
+ "comiss",
+ "cpuid",
+ "cqo",
+ "crc32",
+ "cvtdq2pd",
+ "cvtdq2ps",
+ "cvtpd2dq",
+ "cvtpd2pi",
+ "cvtpd2ps",
+ "cvtpi2pd",
+ "cvtpi2ps",
+ "cvtps2dq",
+ "cvtps2pd",
+ "cvtps2pi",
+ "cvtsd2si",
+ "cvtsd2ss",
+ "cvtsi2sd",
+ "cvtsi2ss",
+ "cvtss2sd",
+ "cvtss2si",
+ "cvttpd2dq",
+ "cvttpd2pi",
+ "cvttps2dq",
+ "cvttps2pi",
+ "cvttsd2si",
+ "cvttss2si",
+ "cwd",
+ "cwde",
+ "daa",
+ "das",
+ "dec",
+ "div",
+ "divpd",
+ "divps",
+ "divsd",
+ "divss",
+ "dppd",
+ "dpps",
+ "emms",
+ "enter",
+ "extractps",
+ "f2xm1",
+ "fabs",
+ "fadd",
+ "faddp",
+ "fbld",
+ "fbstp",
+ "fchs",
+ "fclex",
+ "fcmovb",
+ "fcmovbe",
+ "fcmove",
+ "fcmovnb",
+ "fcmovnbe",
+ "fcmovne",
+ "fcmovnu",
+ "fcmovu",
+ "fcom",
+ "fcom2",
+ "fcomi",
+ "fcomip",
+ "fcomp",
+ "fcomp3",
+ "fcomp5",
+ "fcompp",
+ "fcos",
+ "fdecstp",
+ "fdiv",
+ "fdivp",
+ "fdivr",
+ "fdivrp",
+ "femms",
+ "ffree",
+ "ffreep",
+ "fiadd",
+ "ficom",
+ "ficomp",
+ "fidiv",
+ "fidivr",
+ "fild",
+ "fimul",
+ "fincstp",
+ "fist",
+ "fistp",
+ "fisttp",
+ "fisub",
+ "fisubr",
+ "fld",
+ "fld1",
+ "fldcw",
+ "fldenv",
+ "fldl2e",
+ "fldl2t",
+ "fldlg2",
+ "fldln2",
+ "fldpi",
+ "fldz",
+ "fmul",
+ "fmulp",
+ "fndisi",
+ "fneni",
+ "fninit",
+ "fnop",
+ "fnsave",
+ "fnsetpm",
+ "fnstcw",
+ "fnstenv",
+ "fnstsw",
+ "fpatan",
+ "fprem",
+ "fprem1",
+ "fptan",
+ "frndint",
+ "frstor",
+ "frstpm",
+ "fscale",
+ "fsin",
+ "fsincos",
+ "fsqrt",
+ "fst",
+ "fstp",
+ "fstp1",
+ "fstp8",
+ "fstp9",
+ "fsub",
+ "fsubp",
+ "fsubr",
+ "fsubrp",
+ "ftst",
+ "fucom",
+ "fucomi",
+ "fucomip",
+ "fucomp",
+ "fucompp",
+ "fxam",
+ "fxch",
+ "fxch4",
+ "fxch7",
+ "fxrstor",
+ "fxsave",
+ "fxtract",
+ "fyl2x",
+ "fyl2xp1",
+ "getsec",
+ "haddpd",
+ "haddps",
+ "hlt",
+ "hsubpd",
+ "hsubps",
+ "idiv",
+ "imul",
+ "in",
+ "inc",
+ "insb",
+ "insd",
+ "insertps",
+ "insw",
+ "int",
+ "int1",
+ "int3",
+ "into",
+ "invd",
+ "invept",
+ "invlpg",
+ "invlpga",
+ "invvpid",
+ "iretd",
+ "iretq",
+ "iretw",
+ "ja",
+ "jae",
+ "jb",
+ "jbe",
+ "jcxz",
+ "jecxz",
+ "jg",
+ "jge",
+ "jl",
+ "jle",
+ "jmp",
+ "jno",
+ "jnp",
+ "jns",
+ "jnz",
+ "jo",
+ "jp",
+ "jrcxz",
+ "js",
+ "jz",
+ "lahf",
+ "lar",
+ "lddqu",
+ "ldmxcsr",
+ "lds",
+ "lea",
+ "leave",
+ "les",
+ "lfence",
+ "lfs",
+ "lgdt",
+ "lgs",
+ "lidt",
+ "lldt",
+ "lmsw",
+ "lock",
+ "lodsb",
+ "lodsd",
+ "lodsq",
+ "lodsw",
+ "loop",
+ "loope",
+ "loopne",
+ "lsl",
+ "lss",
+ "ltr",
+ "maskmovdqu",
+ "maskmovq",
+ "maxpd",
+ "maxps",
+ "maxsd",
+ "maxss",
+ "mfence",
+ "minpd",
+ "minps",
+ "minsd",
+ "minss",
+ "monitor",
+ "montmul",
+ "mov",
+ "movapd",
+ "movaps",
+ "movbe",
+ "movd",
+ "movddup",
+ "movdq2q",
+ "movdqa",
+ "movdqu",
+ "movhlps",
+ "movhpd",
+ "movhps",
+ "movlhps",
+ "movlpd",
+ "movlps",
+ "movmskpd",
+ "movmskps",
+ "movntdq",
+ "movntdqa",
+ "movnti",
+ "movntpd",
+ "movntps",
+ "movntq",
+ "movq",
+ "movq2dq",
+ "movsb",
+ "movsd",
+ "movshdup",
+ "movsldup",
+ "movsq",
+ "movss",
+ "movsw",
+ "movsx",
+ "movsxd",
+ "movupd",
+ "movups",
+ "movzx",
+ "mpsadbw",
+ "mul",
+ "mulpd",
+ "mulps",
+ "mulsd",
+ "mulss",
+ "mwait",
+ "neg",
+ "nop",
+ "not",
+ "or",
+ "orpd",
+ "orps",
+ "out",
+ "outsb",
+ "outsd",
+ "outsw",
+ "pabsb",
+ "pabsd",
+ "pabsw",
+ "packssdw",
+ "packsswb",
+ "packusdw",
+ "packuswb",
+ "paddb",
+ "paddd",
+ "paddq",
+ "paddsb",
+ "paddsw",
+ "paddusb",
+ "paddusw",
+ "paddw",
+ "palignr",
+ "pand",
+ "pandn",
+ "pavgb",
+ "pavgusb",
+ "pavgw",
+ "pblendvb",
+ "pblendw",
+ "pclmulqdq",
+ "pcmpeqb",
+ "pcmpeqd",
+ "pcmpeqq",
+ "pcmpeqw",
+ "pcmpestri",
+ "pcmpestrm",
+ "pcmpgtb",
+ "pcmpgtd",
+ "pcmpgtq",
+ "pcmpgtw",
+ "pcmpistri",
+ "pcmpistrm",
+ "pextrb",
+ "pextrd",
+ "pextrq",
+ "pextrw",
+ "pf2id",
+ "pf2iw",
+ "pfacc",
+ "pfadd",
+ "pfcmpeq",
+ "pfcmpge",
+ "pfcmpgt",
+ "pfmax",
+ "pfmin",
+ "pfmul",
+ "pfnacc",
+ "pfpnacc",
+ "pfrcp",
+ "pfrcpit1",
+ "pfrcpit2",
+ "pfrsqit1",
+ "pfrsqrt",
+ "pfsub",
+ "pfsubr",
+ "phaddd",
+ "phaddsw",
+ "phaddw",
+ "phminposuw",
+ "phsubd",
+ "phsubsw",
+ "phsubw",
+ "pi2fd",
+ "pi2fw",
+ "pinsrb",
+ "pinsrd",
+ "pinsrq",
+ "pinsrw",
+ "pmaddubsw",
+ "pmaddwd",
+ "pmaxsb",
+ "pmaxsd",
+ "pmaxsw",
+ "pmaxub",
+ "pmaxud",
+ "pmaxuw",
+ "pminsb",
+ "pminsd",
+ "pminsw",
+ "pminub",
+ "pminud",
+ "pminuw",
+ "pmovmskb",
+ "pmovsxbd",
+ "pmovsxbq",
+ "pmovsxbw",
+ "pmovsxdq",
+ "pmovsxwd",
+ "pmovsxwq",
+ "pmovzxbd",
+ "pmovzxbq",
+ "pmovzxbw",
+ "pmovzxdq",
+ "pmovzxwd",
+ "pmovzxwq",
+ "pmuldq",
+ "pmulhrsw",
+ "pmulhrw",
+ "pmulhuw",
+ "pmulhw",
+ "pmulld",
+ "pmullw",
+ "pmuludq",
+ "pop",
+ "popa",
+ "popad",
+ "popcnt",
+ "popfd",
+ "popfq",
+ "popfw",
+ "por",
+ "prefetch",
+ "prefetchnta",
+ "prefetcht0",
+ "prefetcht1",
+ "prefetcht2",
+ "psadbw",
+ "pshufb",
+ "pshufd",
+ "pshufhw",
+ "pshuflw",
+ "pshufw",
+ "psignb",
+ "psignd",
+ "psignw",
+ "pslld",
+ "pslldq",
+ "psllq",
+ "psllw",
+ "psrad",
+ "psraw",
+ "psrld",
+ "psrldq",
+ "psrlq",
+ "psrlw",
+ "psubb",
+ "psubd",
+ "psubq",
+ "psubsb",
+ "psubsw",
+ "psubusb",
+ "psubusw",
+ "psubw",
+ "pswapd",
+ "ptest",
+ "punpckhbw",
+ "punpckhdq",
+ "punpckhqdq",
+ "punpckhwd",
+ "punpcklbw",
+ "punpckldq",
+ "punpcklqdq",
+ "punpcklwd",
+ "push",
+ "pusha",
+ "pushad",
+ "pushfd",
+ "pushfq",
+ "pushfw",
+ "pxor",
+ "rcl",
+ "rcpps",
+ "rcpss",
+ "rcr",
+ "rdmsr",
+ "rdpmc",
+ "rdrand",
+ "rdtsc",
+ "rdtscp",
+ "rep",
+ "repne",
+ "ret",
+ "retf",
+ "rol",
+ "ror",
+ "roundpd",
+ "roundps",
+ "roundsd",
+ "roundss",
+ "rsm",
+ "rsqrtps",
+ "rsqrtss",
+ "sahf",
+ "salc",
+ "sar",
+ "sbb",
+ "scasb",
+ "scasd",
+ "scasq",
+ "scasw",
+ "seta",
+ "setae",
+ "setb",
+ "setbe",
+ "setg",
+ "setge",
+ "setl",
+ "setle",
+ "setno",
+ "setnp",
+ "setns",
+ "setnz",
+ "seto",
+ "setp",
+ "sets",
+ "setz",
+ "sfence",
+ "sgdt",
+ "shl",
+ "shld",
+ "shr",
+ "shrd",
+ "shufpd",
+ "shufps",
+ "sidt",
+ "skinit",
+ "sldt",
+ "smsw",
+ "sqrtpd",
+ "sqrtps",
+ "sqrtsd",
+ "sqrtss",
+ "stc",
+ "std",
+ "stgi",
+ "sti",
+ "stmxcsr",
+ "stosb",
+ "stosd",
+ "stosq",
+ "stosw",
+ "str",
+ "sub",
+ "subpd",
+ "subps",
+ "subsd",
+ "subss",
+ "swapgs",
+ "syscall",
+ "sysenter",
+ "sysexit",
+ "sysret",
+ "test",
+ "ucomisd",
+ "ucomiss",
+ "ud2",
+ "unpckhpd",
+ "unpckhps",
+ "unpcklpd",
+ "unpcklps",
+ "vaddpd",
+ "vaddps",
+ "vaddsd",
+ "vaddss",
+ "vaddsubpd",
+ "vaddsubps",
+ "vaesdec",
+ "vaesdeclast",
+ "vaesenc",
+ "vaesenclast",
+ "vaesimc",
+ "vaeskeygenassist",
+ "vandnpd",
+ "vandnps",
+ "vandpd",
+ "vandps",
+ "vblendpd",
+ "vblendps",
+ "vblendvpd",
+ "vblendvps",
+ "vbroadcastsd",
+ "vbroadcastss",
+ "vcmppd",
+ "vcmpps",
+ "vcmpsd",
+ "vcmpss",
+ "vcomisd",
+ "vcomiss",
+ "vcvtdq2pd",
+ "vcvtdq2ps",
+ "vcvtpd2dq",
+ "vcvtpd2ps",
+ "vcvtps2dq",
+ "vcvtps2pd",
+ "vcvtsd2si",
+ "vcvtsd2ss",
+ "vcvtsi2sd",
+ "vcvtsi2ss",
+ "vcvtss2sd",
+ "vcvtss2si",
+ "vcvttpd2dq",
+ "vcvttps2dq",
+ "vcvttsd2si",
+ "vcvttss2si",
+ "vdivpd",
+ "vdivps",
+ "vdivsd",
+ "vdivss",
+ "vdppd",
+ "vdpps",
+ "verr",
+ "verw",
+ "vextractf128",
+ "vextractps",
+ "vhaddpd",
+ "vhaddps",
+ "vhsubpd",
+ "vhsubps",
+ "vinsertf128",
+ "vinsertps",
+ "vlddqu",
+ "vmaskmovdqu",
+ "vmaskmovpd",
+ "vmaskmovps",
+ "vmaxpd",
+ "vmaxps",
+ "vmaxsd",
+ "vmaxss",
+ "vmcall",
+ "vmclear",
+ "vminpd",
+ "vminps",
+ "vminsd",
+ "vminss",
+ "vmlaunch",
+ "vmload",
+ "vmmcall",
+ "vmovapd",
+ "vmovaps",
+ "vmovd",
+ "vmovddup",
+ "vmovdqa",
+ "vmovdqu",
+ "vmovhlps",
+ "vmovhpd",
+ "vmovhps",
+ "vmovlhps",
+ "vmovlpd",
+ "vmovlps",
+ "vmovmskpd",
+ "vmovmskps",
+ "vmovntdq",
+ "vmovntdqa",
+ "vmovntpd",
+ "vmovntps",
+ "vmovq",
+ "vmovsd",
+ "vmovshdup",
+ "vmovsldup",
+ "vmovss",
+ "vmovupd",
+ "vmovups",
+ "vmpsadbw",
+ "vmptrld",
+ "vmptrst",
+ "vmread",
+ "vmresume",
+ "vmrun",
+ "vmsave",
+ "vmulpd",
+ "vmulps",
+ "vmulsd",
+ "vmulss",
+ "vmwrite",
+ "vmxoff",
+ "vmxon",
+ "vorpd",
+ "vorps",
+ "vpabsb",
+ "vpabsd",
+ "vpabsw",
+ "vpackssdw",
+ "vpacksswb",
+ "vpackusdw",
+ "vpackuswb",
+ "vpaddb",
+ "vpaddd",
+ "vpaddq",
+ "vpaddsb",
+ "vpaddsw",
+ "vpaddusb",
+ "vpaddusw",
+ "vpaddw",
+ "vpalignr",
+ "vpand",
+ "vpandn",
+ "vpavgb",
+ "vpavgw",
+ "vpblendvb",
+ "vpblendw",
+ "vpclmulqdq",
+ "vpcmpeqb",
+ "vpcmpeqd",
+ "vpcmpeqq",
+ "vpcmpeqw",
+ "vpcmpestri",
+ "vpcmpestrm",
+ "vpcmpgtb",
+ "vpcmpgtd",
+ "vpcmpgtq",
+ "vpcmpgtw",
+ "vpcmpistri",
+ "vpcmpistrm",
+ "vperm2f128",
+ "vpermilpd",
+ "vpermilps",
+ "vpextrb",
+ "vpextrd",
+ "vpextrq",
+ "vpextrw",
+ "vphaddd",
+ "vphaddsw",
+ "vphaddw",
+ "vphminposuw",
+ "vphsubd",
+ "vphsubsw",
+ "vphsubw",
+ "vpinsrb",
+ "vpinsrd",
+ "vpinsrq",
+ "vpinsrw",
+ "vpmaddubsw",
+ "vpmaddwd",
+ "vpmaxsb",
+ "vpmaxsd",
+ "vpmaxsw",
+ "vpmaxub",
+ "vpmaxud",
+ "vpmaxuw",
+ "vpminsb",
+ "vpminsd",
+ "vpminsw",
+ "vpminub",
+ "vpminud",
+ "vpminuw",
+ "vpmovmskb",
+ "vpmovsxbd",
+ "vpmovsxbq",
+ "vpmovsxbw",
+ "vpmovsxwd",
+ "vpmovsxwq",
+ "vpmovzxbd",
+ "vpmovzxbq",
+ "vpmovzxbw",
+ "vpmovzxdq",
+ "vpmovzxwd",
+ "vpmovzxwq",
+ "vpmuldq",
+ "vpmulhrsw",
+ "vpmulhuw",
+ "vpmulhw",
+ "vpmulld",
+ "vpmullw",
+ "vpor",
+ "vpsadbw",
+ "vpshufb",
+ "vpshufd",
+ "vpshufhw",
+ "vpshuflw",
+ "vpsignb",
+ "vpsignd",
+ "vpsignw",
+ "vpslld",
+ "vpslldq",
+ "vpsllq",
+ "vpsllw",
+ "vpsrad",
+ "vpsraw",
+ "vpsrld",
+ "vpsrldq",
+ "vpsrlq",
+ "vpsrlw",
+ "vpsubb",
+ "vpsubd",
+ "vpsubq",
+ "vpsubsb",
+ "vpsubsw",
+ "vpsubusb",
+ "vpsubusw",
+ "vpsubw",
+ "vptest",
+ "vpunpckhbw",
+ "vpunpckhdq",
+ "vpunpckhqdq",
+ "vpunpckhwd",
+ "vpunpcklbw",
+ "vpunpckldq",
+ "vpunpcklqdq",
+ "vpunpcklwd",
+ "vpxor",
+ "vrcpps",
+ "vrcpss",
+ "vroundpd",
+ "vroundps",
+ "vroundsd",
+ "vroundss",
+ "vrsqrtps",
+ "vrsqrtss",
+ "vshufpd",
+ "vshufps",
+ "vsqrtpd",
+ "vsqrtps",
+ "vsqrtsd",
+ "vsqrtss",
+ "vstmxcsr",
+ "vsubpd",
+ "vsubps",
+ "vsubsd",
+ "vsubss",
+ "vtestpd",
+ "vtestps",
+ "vucomisd",
+ "vucomiss",
+ "vunpckhpd",
+ "vunpckhps",
+ "vunpcklpd",
+ "vunpcklps",
+ "vxorpd",
+ "vxorps",
+ "vzeroall",
+ "vzeroupper",
+ "wait",
+ "wbinvd",
+ "wrmsr",
+ "xadd",
+ "xchg",
+ "xcryptcbc",
+ "xcryptcfb",
+ "xcryptctr",
+ "xcryptecb",
+ "xcryptofb",
+ "xgetbv",
+ "xlatb",
+ "xor",
+ "xorpd",
+ "xorps",
+ "xrstor",
+ "xsave",
+ "xsetbv",
+ "xsha1",
+ "xsha256",
+ "xstore",
+ "invalid",
+ "3dnow",
+ "none",
+ "db",
+ "pause"
+};
diff --git a/ext/opcache/jit/libudis86/itab.h b/ext/opcache/jit/libudis86/itab.h
new file mode 100644
index 0000000000..3d54c43546
--- /dev/null
+++ b/ext/opcache/jit/libudis86/itab.h
@@ -0,0 +1,939 @@
+#ifndef UD_ITAB_H
+#define UD_ITAB_H
+
+/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */
+
+/* ud_table_type -- lookup table types (see decode.c) */
+enum ud_table_type {
+ UD_TAB__OPC_VEX,
+ UD_TAB__OPC_TABLE,
+ UD_TAB__OPC_X87,
+ UD_TAB__OPC_MOD,
+ UD_TAB__OPC_RM,
+ UD_TAB__OPC_OSIZE,
+ UD_TAB__OPC_MODE,
+ UD_TAB__OPC_VEX_L,
+ UD_TAB__OPC_3DNOW,
+ UD_TAB__OPC_REG,
+ UD_TAB__OPC_ASIZE,
+ UD_TAB__OPC_VEX_W,
+ UD_TAB__OPC_SSE,
+ UD_TAB__OPC_VENDOR
+};
+
+/* ud_mnemonic -- mnemonic constants */
+enum ud_mnemonic_code {
+ UD_Iaaa,
+ UD_Iaad,
+ UD_Iaam,
+ UD_Iaas,
+ UD_Iadc,
+ UD_Iadd,
+ UD_Iaddpd,
+ UD_Iaddps,
+ UD_Iaddsd,
+ UD_Iaddss,
+ UD_Iaddsubpd,
+ UD_Iaddsubps,
+ UD_Iaesdec,
+ UD_Iaesdeclast,
+ UD_Iaesenc,
+ UD_Iaesenclast,
+ UD_Iaesimc,
+ UD_Iaeskeygenassist,
+ UD_Iand,
+ UD_Iandnpd,
+ UD_Iandnps,
+ UD_Iandpd,
+ UD_Iandps,
+ UD_Iarpl,
+ UD_Iblendpd,
+ UD_Iblendps,
+ UD_Iblendvpd,
+ UD_Iblendvps,
+ UD_Ibound,
+ UD_Ibsf,
+ UD_Ibsr,
+ UD_Ibswap,
+ UD_Ibt,
+ UD_Ibtc,
+ UD_Ibtr,
+ UD_Ibts,
+ UD_Icall,
+ UD_Icbw,
+ UD_Icdq,
+ UD_Icdqe,
+ UD_Iclc,
+ UD_Icld,
+ UD_Iclflush,
+ UD_Iclgi,
+ UD_Icli,
+ UD_Iclts,
+ UD_Icmc,
+ UD_Icmova,
+ UD_Icmovae,
+ UD_Icmovb,
+ UD_Icmovbe,
+ UD_Icmovg,
+ UD_Icmovge,
+ UD_Icmovl,
+ UD_Icmovle,
+ UD_Icmovno,
+ UD_Icmovnp,
+ UD_Icmovns,
+ UD_Icmovnz,
+ UD_Icmovo,
+ UD_Icmovp,
+ UD_Icmovs,
+ UD_Icmovz,
+ UD_Icmp,
+ UD_Icmppd,
+ UD_Icmpps,
+ UD_Icmpsb,
+ UD_Icmpsd,
+ UD_Icmpsq,
+ UD_Icmpss,
+ UD_Icmpsw,
+ UD_Icmpxchg,
+ UD_Icmpxchg16b,
+ UD_Icmpxchg8b,
+ UD_Icomisd,
+ UD_Icomiss,
+ UD_Icpuid,
+ UD_Icqo,
+ UD_Icrc32,
+ UD_Icvtdq2pd,
+ UD_Icvtdq2ps,
+ UD_Icvtpd2dq,
+ UD_Icvtpd2pi,
+ UD_Icvtpd2ps,
+ UD_Icvtpi2pd,
+ UD_Icvtpi2ps,
+ UD_Icvtps2dq,
+ UD_Icvtps2pd,
+ UD_Icvtps2pi,
+ UD_Icvtsd2si,
+ UD_Icvtsd2ss,
+ UD_Icvtsi2sd,
+ UD_Icvtsi2ss,
+ UD_Icvtss2sd,
+ UD_Icvtss2si,
+ UD_Icvttpd2dq,
+ UD_Icvttpd2pi,
+ UD_Icvttps2dq,
+ UD_Icvttps2pi,
+ UD_Icvttsd2si,
+ UD_Icvttss2si,
+ UD_Icwd,
+ UD_Icwde,
+ UD_Idaa,
+ UD_Idas,
+ UD_Idec,
+ UD_Idiv,
+ UD_Idivpd,
+ UD_Idivps,
+ UD_Idivsd,
+ UD_Idivss,
+ UD_Idppd,
+ UD_Idpps,
+ UD_Iemms,
+ UD_Ienter,
+ UD_Iextractps,
+ UD_If2xm1,
+ UD_Ifabs,
+ UD_Ifadd,
+ UD_Ifaddp,
+ UD_Ifbld,
+ UD_Ifbstp,
+ UD_Ifchs,
+ UD_Ifclex,
+ UD_Ifcmovb,
+ UD_Ifcmovbe,
+ UD_Ifcmove,
+ UD_Ifcmovnb,
+ UD_Ifcmovnbe,
+ UD_Ifcmovne,
+ UD_Ifcmovnu,
+ UD_Ifcmovu,
+ UD_Ifcom,
+ UD_Ifcom2,
+ UD_Ifcomi,
+ UD_Ifcomip,
+ UD_Ifcomp,
+ UD_Ifcomp3,
+ UD_Ifcomp5,
+ UD_Ifcompp,
+ UD_Ifcos,
+ UD_Ifdecstp,
+ UD_Ifdiv,
+ UD_Ifdivp,
+ UD_Ifdivr,
+ UD_Ifdivrp,
+ UD_Ifemms,
+ UD_Iffree,
+ UD_Iffreep,
+ UD_Ifiadd,
+ UD_Ificom,
+ UD_Ificomp,
+ UD_Ifidiv,
+ UD_Ifidivr,
+ UD_Ifild,
+ UD_Ifimul,
+ UD_Ifincstp,
+ UD_Ifist,
+ UD_Ifistp,
+ UD_Ifisttp,
+ UD_Ifisub,
+ UD_Ifisubr,
+ UD_Ifld,
+ UD_Ifld1,
+ UD_Ifldcw,
+ UD_Ifldenv,
+ UD_Ifldl2e,
+ UD_Ifldl2t,
+ UD_Ifldlg2,
+ UD_Ifldln2,
+ UD_Ifldpi,
+ UD_Ifldz,
+ UD_Ifmul,
+ UD_Ifmulp,
+ UD_Ifndisi,
+ UD_Ifneni,
+ UD_Ifninit,
+ UD_Ifnop,
+ UD_Ifnsave,
+ UD_Ifnsetpm,
+ UD_Ifnstcw,
+ UD_Ifnstenv,
+ UD_Ifnstsw,
+ UD_Ifpatan,
+ UD_Ifprem,
+ UD_Ifprem1,
+ UD_Ifptan,
+ UD_Ifrndint,
+ UD_Ifrstor,
+ UD_Ifrstpm,
+ UD_Ifscale,
+ UD_Ifsin,
+ UD_Ifsincos,
+ UD_Ifsqrt,
+ UD_Ifst,
+ UD_Ifstp,
+ UD_Ifstp1,
+ UD_Ifstp8,
+ UD_Ifstp9,
+ UD_Ifsub,
+ UD_Ifsubp,
+ UD_Ifsubr,
+ UD_Ifsubrp,
+ UD_Iftst,
+ UD_Ifucom,
+ UD_Ifucomi,
+ UD_Ifucomip,
+ UD_Ifucomp,
+ UD_Ifucompp,
+ UD_Ifxam,
+ UD_Ifxch,
+ UD_Ifxch4,
+ UD_Ifxch7,
+ UD_Ifxrstor,
+ UD_Ifxsave,
+ UD_Ifxtract,
+ UD_Ifyl2x,
+ UD_Ifyl2xp1,
+ UD_Igetsec,
+ UD_Ihaddpd,
+ UD_Ihaddps,
+ UD_Ihlt,
+ UD_Ihsubpd,
+ UD_Ihsubps,
+ UD_Iidiv,
+ UD_Iimul,
+ UD_Iin,
+ UD_Iinc,
+ UD_Iinsb,
+ UD_Iinsd,
+ UD_Iinsertps,
+ UD_Iinsw,
+ UD_Iint,
+ UD_Iint1,
+ UD_Iint3,
+ UD_Iinto,
+ UD_Iinvd,
+ UD_Iinvept,
+ UD_Iinvlpg,
+ UD_Iinvlpga,
+ UD_Iinvvpid,
+ UD_Iiretd,
+ UD_Iiretq,
+ UD_Iiretw,
+ UD_Ija,
+ UD_Ijae,
+ UD_Ijb,
+ UD_Ijbe,
+ UD_Ijcxz,
+ UD_Ijecxz,
+ UD_Ijg,
+ UD_Ijge,
+ UD_Ijl,
+ UD_Ijle,
+ UD_Ijmp,
+ UD_Ijno,
+ UD_Ijnp,
+ UD_Ijns,
+ UD_Ijnz,
+ UD_Ijo,
+ UD_Ijp,
+ UD_Ijrcxz,
+ UD_Ijs,
+ UD_Ijz,
+ UD_Ilahf,
+ UD_Ilar,
+ UD_Ilddqu,
+ UD_Ildmxcsr,
+ UD_Ilds,
+ UD_Ilea,
+ UD_Ileave,
+ UD_Iles,
+ UD_Ilfence,
+ UD_Ilfs,
+ UD_Ilgdt,
+ UD_Ilgs,
+ UD_Ilidt,
+ UD_Illdt,
+ UD_Ilmsw,
+ UD_Ilock,
+ UD_Ilodsb,
+ UD_Ilodsd,
+ UD_Ilodsq,
+ UD_Ilodsw,
+ UD_Iloop,
+ UD_Iloope,
+ UD_Iloopne,
+ UD_Ilsl,
+ UD_Ilss,
+ UD_Iltr,
+ UD_Imaskmovdqu,
+ UD_Imaskmovq,
+ UD_Imaxpd,
+ UD_Imaxps,
+ UD_Imaxsd,
+ UD_Imaxss,
+ UD_Imfence,
+ UD_Iminpd,
+ UD_Iminps,
+ UD_Iminsd,
+ UD_Iminss,
+ UD_Imonitor,
+ UD_Imontmul,
+ UD_Imov,
+ UD_Imovapd,
+ UD_Imovaps,
+ UD_Imovbe,
+ UD_Imovd,
+ UD_Imovddup,
+ UD_Imovdq2q,
+ UD_Imovdqa,
+ UD_Imovdqu,
+ UD_Imovhlps,
+ UD_Imovhpd,
+ UD_Imovhps,
+ UD_Imovlhps,
+ UD_Imovlpd,
+ UD_Imovlps,
+ UD_Imovmskpd,
+ UD_Imovmskps,
+ UD_Imovntdq,
+ UD_Imovntdqa,
+ UD_Imovnti,
+ UD_Imovntpd,
+ UD_Imovntps,
+ UD_Imovntq,
+ UD_Imovq,
+ UD_Imovq2dq,
+ UD_Imovsb,
+ UD_Imovsd,
+ UD_Imovshdup,
+ UD_Imovsldup,
+ UD_Imovsq,
+ UD_Imovss,
+ UD_Imovsw,
+ UD_Imovsx,
+ UD_Imovsxd,
+ UD_Imovupd,
+ UD_Imovups,
+ UD_Imovzx,
+ UD_Impsadbw,
+ UD_Imul,
+ UD_Imulpd,
+ UD_Imulps,
+ UD_Imulsd,
+ UD_Imulss,
+ UD_Imwait,
+ UD_Ineg,
+ UD_Inop,
+ UD_Inot,
+ UD_Ior,
+ UD_Iorpd,
+ UD_Iorps,
+ UD_Iout,
+ UD_Ioutsb,
+ UD_Ioutsd,
+ UD_Ioutsw,
+ UD_Ipabsb,
+ UD_Ipabsd,
+ UD_Ipabsw,
+ UD_Ipackssdw,
+ UD_Ipacksswb,
+ UD_Ipackusdw,
+ UD_Ipackuswb,
+ UD_Ipaddb,
+ UD_Ipaddd,
+ UD_Ipaddq,
+ UD_Ipaddsb,
+ UD_Ipaddsw,
+ UD_Ipaddusb,
+ UD_Ipaddusw,
+ UD_Ipaddw,
+ UD_Ipalignr,
+ UD_Ipand,
+ UD_Ipandn,
+ UD_Ipavgb,
+ UD_Ipavgusb,
+ UD_Ipavgw,
+ UD_Ipblendvb,
+ UD_Ipblendw,
+ UD_Ipclmulqdq,
+ UD_Ipcmpeqb,
+ UD_Ipcmpeqd,
+ UD_Ipcmpeqq,
+ UD_Ipcmpeqw,
+ UD_Ipcmpestri,
+ UD_Ipcmpestrm,
+ UD_Ipcmpgtb,
+ UD_Ipcmpgtd,
+ UD_Ipcmpgtq,
+ UD_Ipcmpgtw,
+ UD_Ipcmpistri,
+ UD_Ipcmpistrm,
+ UD_Ipextrb,
+ UD_Ipextrd,
+ UD_Ipextrq,
+ UD_Ipextrw,
+ UD_Ipf2id,
+ UD_Ipf2iw,
+ UD_Ipfacc,
+ UD_Ipfadd,
+ UD_Ipfcmpeq,
+ UD_Ipfcmpge,
+ UD_Ipfcmpgt,
+ UD_Ipfmax,
+ UD_Ipfmin,
+ UD_Ipfmul,
+ UD_Ipfnacc,
+ UD_Ipfpnacc,
+ UD_Ipfrcp,
+ UD_Ipfrcpit1,
+ UD_Ipfrcpit2,
+ UD_Ipfrsqit1,
+ UD_Ipfrsqrt,
+ UD_Ipfsub,
+ UD_Ipfsubr,
+ UD_Iphaddd,
+ UD_Iphaddsw,
+ UD_Iphaddw,
+ UD_Iphminposuw,
+ UD_Iphsubd,
+ UD_Iphsubsw,
+ UD_Iphsubw,
+ UD_Ipi2fd,
+ UD_Ipi2fw,
+ UD_Ipinsrb,
+ UD_Ipinsrd,
+ UD_Ipinsrq,
+ UD_Ipinsrw,
+ UD_Ipmaddubsw,
+ UD_Ipmaddwd,
+ UD_Ipmaxsb,
+ UD_Ipmaxsd,
+ UD_Ipmaxsw,
+ UD_Ipmaxub,
+ UD_Ipmaxud,
+ UD_Ipmaxuw,
+ UD_Ipminsb,
+ UD_Ipminsd,
+ UD_Ipminsw,
+ UD_Ipminub,
+ UD_Ipminud,
+ UD_Ipminuw,
+ UD_Ipmovmskb,
+ UD_Ipmovsxbd,
+ UD_Ipmovsxbq,
+ UD_Ipmovsxbw,
+ UD_Ipmovsxdq,
+ UD_Ipmovsxwd,
+ UD_Ipmovsxwq,
+ UD_Ipmovzxbd,
+ UD_Ipmovzxbq,
+ UD_Ipmovzxbw,
+ UD_Ipmovzxdq,
+ UD_Ipmovzxwd,
+ UD_Ipmovzxwq,
+ UD_Ipmuldq,
+ UD_Ipmulhrsw,
+ UD_Ipmulhrw,
+ UD_Ipmulhuw,
+ UD_Ipmulhw,
+ UD_Ipmulld,
+ UD_Ipmullw,
+ UD_Ipmuludq,
+ UD_Ipop,
+ UD_Ipopa,
+ UD_Ipopad,
+ UD_Ipopcnt,
+ UD_Ipopfd,
+ UD_Ipopfq,
+ UD_Ipopfw,
+ UD_Ipor,
+ UD_Iprefetch,
+ UD_Iprefetchnta,
+ UD_Iprefetcht0,
+ UD_Iprefetcht1,
+ UD_Iprefetcht2,
+ UD_Ipsadbw,
+ UD_Ipshufb,
+ UD_Ipshufd,
+ UD_Ipshufhw,
+ UD_Ipshuflw,
+ UD_Ipshufw,
+ UD_Ipsignb,
+ UD_Ipsignd,
+ UD_Ipsignw,
+ UD_Ipslld,
+ UD_Ipslldq,
+ UD_Ipsllq,
+ UD_Ipsllw,
+ UD_Ipsrad,
+ UD_Ipsraw,
+ UD_Ipsrld,
+ UD_Ipsrldq,
+ UD_Ipsrlq,
+ UD_Ipsrlw,
+ UD_Ipsubb,
+ UD_Ipsubd,
+ UD_Ipsubq,
+ UD_Ipsubsb,
+ UD_Ipsubsw,
+ UD_Ipsubusb,
+ UD_Ipsubusw,
+ UD_Ipsubw,
+ UD_Ipswapd,
+ UD_Iptest,
+ UD_Ipunpckhbw,
+ UD_Ipunpckhdq,
+ UD_Ipunpckhqdq,
+ UD_Ipunpckhwd,
+ UD_Ipunpcklbw,
+ UD_Ipunpckldq,
+ UD_Ipunpcklqdq,
+ UD_Ipunpcklwd,
+ UD_Ipush,
+ UD_Ipusha,
+ UD_Ipushad,
+ UD_Ipushfd,
+ UD_Ipushfq,
+ UD_Ipushfw,
+ UD_Ipxor,
+ UD_Ircl,
+ UD_Ircpps,
+ UD_Ircpss,
+ UD_Ircr,
+ UD_Irdmsr,
+ UD_Irdpmc,
+ UD_Irdrand,
+ UD_Irdtsc,
+ UD_Irdtscp,
+ UD_Irep,
+ UD_Irepne,
+ UD_Iret,
+ UD_Iretf,
+ UD_Irol,
+ UD_Iror,
+ UD_Iroundpd,
+ UD_Iroundps,
+ UD_Iroundsd,
+ UD_Iroundss,
+ UD_Irsm,
+ UD_Irsqrtps,
+ UD_Irsqrtss,
+ UD_Isahf,
+ UD_Isalc,
+ UD_Isar,
+ UD_Isbb,
+ UD_Iscasb,
+ UD_Iscasd,
+ UD_Iscasq,
+ UD_Iscasw,
+ UD_Iseta,
+ UD_Isetae,
+ UD_Isetb,
+ UD_Isetbe,
+ UD_Isetg,
+ UD_Isetge,
+ UD_Isetl,
+ UD_Isetle,
+ UD_Isetno,
+ UD_Isetnp,
+ UD_Isetns,
+ UD_Isetnz,
+ UD_Iseto,
+ UD_Isetp,
+ UD_Isets,
+ UD_Isetz,
+ UD_Isfence,
+ UD_Isgdt,
+ UD_Ishl,
+ UD_Ishld,
+ UD_Ishr,
+ UD_Ishrd,
+ UD_Ishufpd,
+ UD_Ishufps,
+ UD_Isidt,
+ UD_Iskinit,
+ UD_Isldt,
+ UD_Ismsw,
+ UD_Isqrtpd,
+ UD_Isqrtps,
+ UD_Isqrtsd,
+ UD_Isqrtss,
+ UD_Istc,
+ UD_Istd,
+ UD_Istgi,
+ UD_Isti,
+ UD_Istmxcsr,
+ UD_Istosb,
+ UD_Istosd,
+ UD_Istosq,
+ UD_Istosw,
+ UD_Istr,
+ UD_Isub,
+ UD_Isubpd,
+ UD_Isubps,
+ UD_Isubsd,
+ UD_Isubss,
+ UD_Iswapgs,
+ UD_Isyscall,
+ UD_Isysenter,
+ UD_Isysexit,
+ UD_Isysret,
+ UD_Itest,
+ UD_Iucomisd,
+ UD_Iucomiss,
+ UD_Iud2,
+ UD_Iunpckhpd,
+ UD_Iunpckhps,
+ UD_Iunpcklpd,
+ UD_Iunpcklps,
+ UD_Ivaddpd,
+ UD_Ivaddps,
+ UD_Ivaddsd,
+ UD_Ivaddss,
+ UD_Ivaddsubpd,
+ UD_Ivaddsubps,
+ UD_Ivaesdec,
+ UD_Ivaesdeclast,
+ UD_Ivaesenc,
+ UD_Ivaesenclast,
+ UD_Ivaesimc,
+ UD_Ivaeskeygenassist,
+ UD_Ivandnpd,
+ UD_Ivandnps,
+ UD_Ivandpd,
+ UD_Ivandps,
+ UD_Ivblendpd,
+ UD_Ivblendps,
+ UD_Ivblendvpd,
+ UD_Ivblendvps,
+ UD_Ivbroadcastsd,
+ UD_Ivbroadcastss,
+ UD_Ivcmppd,
+ UD_Ivcmpps,
+ UD_Ivcmpsd,
+ UD_Ivcmpss,
+ UD_Ivcomisd,
+ UD_Ivcomiss,
+ UD_Ivcvtdq2pd,
+ UD_Ivcvtdq2ps,
+ UD_Ivcvtpd2dq,
+ UD_Ivcvtpd2ps,
+ UD_Ivcvtps2dq,
+ UD_Ivcvtps2pd,
+ UD_Ivcvtsd2si,
+ UD_Ivcvtsd2ss,
+ UD_Ivcvtsi2sd,
+ UD_Ivcvtsi2ss,
+ UD_Ivcvtss2sd,
+ UD_Ivcvtss2si,
+ UD_Ivcvttpd2dq,
+ UD_Ivcvttps2dq,
+ UD_Ivcvttsd2si,
+ UD_Ivcvttss2si,
+ UD_Ivdivpd,
+ UD_Ivdivps,
+ UD_Ivdivsd,
+ UD_Ivdivss,
+ UD_Ivdppd,
+ UD_Ivdpps,
+ UD_Iverr,
+ UD_Iverw,
+ UD_Ivextractf128,
+ UD_Ivextractps,
+ UD_Ivhaddpd,
+ UD_Ivhaddps,
+ UD_Ivhsubpd,
+ UD_Ivhsubps,
+ UD_Ivinsertf128,
+ UD_Ivinsertps,
+ UD_Ivlddqu,
+ UD_Ivmaskmovdqu,
+ UD_Ivmaskmovpd,
+ UD_Ivmaskmovps,
+ UD_Ivmaxpd,
+ UD_Ivmaxps,
+ UD_Ivmaxsd,
+ UD_Ivmaxss,
+ UD_Ivmcall,
+ UD_Ivmclear,
+ UD_Ivminpd,
+ UD_Ivminps,
+ UD_Ivminsd,
+ UD_Ivminss,
+ UD_Ivmlaunch,
+ UD_Ivmload,
+ UD_Ivmmcall,
+ UD_Ivmovapd,
+ UD_Ivmovaps,
+ UD_Ivmovd,
+ UD_Ivmovddup,
+ UD_Ivmovdqa,
+ UD_Ivmovdqu,
+ UD_Ivmovhlps,
+ UD_Ivmovhpd,
+ UD_Ivmovhps,
+ UD_Ivmovlhps,
+ UD_Ivmovlpd,
+ UD_Ivmovlps,
+ UD_Ivmovmskpd,
+ UD_Ivmovmskps,
+ UD_Ivmovntdq,
+ UD_Ivmovntdqa,
+ UD_Ivmovntpd,
+ UD_Ivmovntps,
+ UD_Ivmovq,
+ UD_Ivmovsd,
+ UD_Ivmovshdup,
+ UD_Ivmovsldup,
+ UD_Ivmovss,
+ UD_Ivmovupd,
+ UD_Ivmovups,
+ UD_Ivmpsadbw,
+ UD_Ivmptrld,
+ UD_Ivmptrst,
+ UD_Ivmread,
+ UD_Ivmresume,
+ UD_Ivmrun,
+ UD_Ivmsave,
+ UD_Ivmulpd,
+ UD_Ivmulps,
+ UD_Ivmulsd,
+ UD_Ivmulss,
+ UD_Ivmwrite,
+ UD_Ivmxoff,
+ UD_Ivmxon,
+ UD_Ivorpd,
+ UD_Ivorps,
+ UD_Ivpabsb,
+ UD_Ivpabsd,
+ UD_Ivpabsw,
+ UD_Ivpackssdw,
+ UD_Ivpacksswb,
+ UD_Ivpackusdw,
+ UD_Ivpackuswb,
+ UD_Ivpaddb,
+ UD_Ivpaddd,
+ UD_Ivpaddq,
+ UD_Ivpaddsb,
+ UD_Ivpaddsw,
+ UD_Ivpaddusb,
+ UD_Ivpaddusw,
+ UD_Ivpaddw,
+ UD_Ivpalignr,
+ UD_Ivpand,
+ UD_Ivpandn,
+ UD_Ivpavgb,
+ UD_Ivpavgw,
+ UD_Ivpblendvb,
+ UD_Ivpblendw,
+ UD_Ivpclmulqdq,
+ UD_Ivpcmpeqb,
+ UD_Ivpcmpeqd,
+ UD_Ivpcmpeqq,
+ UD_Ivpcmpeqw,
+ UD_Ivpcmpestri,
+ UD_Ivpcmpestrm,
+ UD_Ivpcmpgtb,
+ UD_Ivpcmpgtd,
+ UD_Ivpcmpgtq,
+ UD_Ivpcmpgtw,
+ UD_Ivpcmpistri,
+ UD_Ivpcmpistrm,
+ UD_Ivperm2f128,
+ UD_Ivpermilpd,
+ UD_Ivpermilps,
+ UD_Ivpextrb,
+ UD_Ivpextrd,
+ UD_Ivpextrq,
+ UD_Ivpextrw,
+ UD_Ivphaddd,
+ UD_Ivphaddsw,
+ UD_Ivphaddw,
+ UD_Ivphminposuw,
+ UD_Ivphsubd,
+ UD_Ivphsubsw,
+ UD_Ivphsubw,
+ UD_Ivpinsrb,
+ UD_Ivpinsrd,
+ UD_Ivpinsrq,
+ UD_Ivpinsrw,
+ UD_Ivpmaddubsw,
+ UD_Ivpmaddwd,
+ UD_Ivpmaxsb,
+ UD_Ivpmaxsd,
+ UD_Ivpmaxsw,
+ UD_Ivpmaxub,
+ UD_Ivpmaxud,
+ UD_Ivpmaxuw,
+ UD_Ivpminsb,
+ UD_Ivpminsd,
+ UD_Ivpminsw,
+ UD_Ivpminub,
+ UD_Ivpminud,
+ UD_Ivpminuw,
+ UD_Ivpmovmskb,
+ UD_Ivpmovsxbd,
+ UD_Ivpmovsxbq,
+ UD_Ivpmovsxbw,
+ UD_Ivpmovsxwd,
+ UD_Ivpmovsxwq,
+ UD_Ivpmovzxbd,
+ UD_Ivpmovzxbq,
+ UD_Ivpmovzxbw,
+ UD_Ivpmovzxdq,
+ UD_Ivpmovzxwd,
+ UD_Ivpmovzxwq,
+ UD_Ivpmuldq,
+ UD_Ivpmulhrsw,
+ UD_Ivpmulhuw,
+ UD_Ivpmulhw,
+ UD_Ivpmulld,
+ UD_Ivpmullw,
+ UD_Ivpor,
+ UD_Ivpsadbw,
+ UD_Ivpshufb,
+ UD_Ivpshufd,
+ UD_Ivpshufhw,
+ UD_Ivpshuflw,
+ UD_Ivpsignb,
+ UD_Ivpsignd,
+ UD_Ivpsignw,
+ UD_Ivpslld,
+ UD_Ivpslldq,
+ UD_Ivpsllq,
+ UD_Ivpsllw,
+ UD_Ivpsrad,
+ UD_Ivpsraw,
+ UD_Ivpsrld,
+ UD_Ivpsrldq,
+ UD_Ivpsrlq,
+ UD_Ivpsrlw,
+ UD_Ivpsubb,
+ UD_Ivpsubd,
+ UD_Ivpsubq,
+ UD_Ivpsubsb,
+ UD_Ivpsubsw,
+ UD_Ivpsubusb,
+ UD_Ivpsubusw,
+ UD_Ivpsubw,
+ UD_Ivptest,
+ UD_Ivpunpckhbw,
+ UD_Ivpunpckhdq,
+ UD_Ivpunpckhqdq,
+ UD_Ivpunpckhwd,
+ UD_Ivpunpcklbw,
+ UD_Ivpunpckldq,
+ UD_Ivpunpcklqdq,
+ UD_Ivpunpcklwd,
+ UD_Ivpxor,
+ UD_Ivrcpps,
+ UD_Ivrcpss,
+ UD_Ivroundpd,
+ UD_Ivroundps,
+ UD_Ivroundsd,
+ UD_Ivroundss,
+ UD_Ivrsqrtps,
+ UD_Ivrsqrtss,
+ UD_Ivshufpd,
+ UD_Ivshufps,
+ UD_Ivsqrtpd,
+ UD_Ivsqrtps,
+ UD_Ivsqrtsd,
+ UD_Ivsqrtss,
+ UD_Ivstmxcsr,
+ UD_Ivsubpd,
+ UD_Ivsubps,
+ UD_Ivsubsd,
+ UD_Ivsubss,
+ UD_Ivtestpd,
+ UD_Ivtestps,
+ UD_Ivucomisd,
+ UD_Ivucomiss,
+ UD_Ivunpckhpd,
+ UD_Ivunpckhps,
+ UD_Ivunpcklpd,
+ UD_Ivunpcklps,
+ UD_Ivxorpd,
+ UD_Ivxorps,
+ UD_Ivzeroall,
+ UD_Ivzeroupper,
+ UD_Iwait,
+ UD_Iwbinvd,
+ UD_Iwrmsr,
+ UD_Ixadd,
+ UD_Ixchg,
+ UD_Ixcryptcbc,
+ UD_Ixcryptcfb,
+ UD_Ixcryptctr,
+ UD_Ixcryptecb,
+ UD_Ixcryptofb,
+ UD_Ixgetbv,
+ UD_Ixlatb,
+ UD_Ixor,
+ UD_Ixorpd,
+ UD_Ixorps,
+ UD_Ixrstor,
+ UD_Ixsave,
+ UD_Ixsetbv,
+ UD_Ixsha1,
+ UD_Ixsha256,
+ UD_Ixstore,
+ UD_Iinvalid,
+ UD_I3dnow,
+ UD_Inone,
+ UD_Idb,
+ UD_Ipause,
+ UD_MAX_MNEMONIC_CODE
+};
+
+extern const char * ud_mnemonics_str[];
+
+#endif /* UD_ITAB_H */
diff --git a/ext/opcache/jit/libudis86/syn-att.c b/ext/opcache/jit/libudis86/syn-att.c
new file mode 100644
index 0000000000..d1ba89b7ae
--- /dev/null
+++ b/ext/opcache/jit/libudis86/syn-att.c
@@ -0,0 +1,228 @@
+/* udis86 - libudis86/syn-att.c
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "types.h"
+#include "extern.h"
+#include "decode.h"
+#include "itab.h"
+#include "syn.h"
+#include "udint.h"
+
+/* -----------------------------------------------------------------------------
+ * opr_cast() - Prints an operand cast.
+ * -----------------------------------------------------------------------------
+ */
+static void
+opr_cast(struct ud* u, struct ud_operand* op)
+{
+ switch(op->size) {
+ case 16 : case 32 :
+ ud_asmprintf(u, "*"); break;
+ default: break;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * gen_operand() - Generates assembly output for each operand.
+ * -----------------------------------------------------------------------------
+ */
+static void
+gen_operand(struct ud* u, struct ud_operand* op)
+{
+ switch(op->type) {
+ case UD_OP_CONST:
+ ud_asmprintf(u, "$0x%x", op->lval.udword);
+ break;
+
+ case UD_OP_REG:
+ ud_asmprintf(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]);
+ break;
+
+ case UD_OP_MEM:
+ if (u->br_far) {
+ opr_cast(u, op);
+ }
+ if (u->pfx_seg) {
+ ud_asmprintf(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
+ }
+ if (op->offset != 0) {
+ ud_syn_print_mem_disp(u, op, 0);
+ }
+ if (op->base) {
+ ud_asmprintf(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]);
+ }
+ if (op->index) {
+ if (op->base) {
+ ud_asmprintf(u, ",");
+ } else {
+ ud_asmprintf(u, "(");
+ }
+ ud_asmprintf(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]);
+ }
+ if (op->scale) {
+ ud_asmprintf(u, ",%d", op->scale);
+ }
+ if (op->base || op->index) {
+ ud_asmprintf(u, ")");
+ }
+ break;
+
+ case UD_OP_IMM:
+ ud_asmprintf(u, "$");
+ ud_syn_print_imm(u, op);
+ break;
+
+ case UD_OP_JIMM:
+ ud_syn_print_addr(u, ud_syn_rel_target(u, op));
+ break;
+
+ case UD_OP_PTR:
+ switch (op->size) {
+ case 32:
+ ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off & 0xFFFF);
+ break;
+ case 48:
+ ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off);
+ break;
+ }
+ break;
+
+ default: return;
+ }
+}
+
+/* =============================================================================
+ * translates to AT&T syntax
+ * =============================================================================
+ */
+extern void
+ud_translate_att(struct ud *u)
+{
+ int size = 0;
+ int star = 0;
+
+ /* check if P_OSO prefix is used */
+ if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
+ switch (u->dis_mode) {
+ case 16:
+ ud_asmprintf(u, "o32 ");
+ break;
+ case 32:
+ case 64:
+ ud_asmprintf(u, "o16 ");
+ break;
+ }
+ }
+
+ /* check if P_ASO prefix was used */
+ if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
+ switch (u->dis_mode) {
+ case 16:
+ ud_asmprintf(u, "a32 ");
+ break;
+ case 32:
+ ud_asmprintf(u, "a16 ");
+ break;
+ case 64:
+ ud_asmprintf(u, "a32 ");
+ break;
+ }
+ }
+
+ if (u->pfx_lock)
+ ud_asmprintf(u, "lock ");
+ if (u->pfx_rep) {
+ ud_asmprintf(u, "rep ");
+ } else if (u->pfx_repe) {
+ ud_asmprintf(u, "repe ");
+ } else if (u->pfx_repne) {
+ ud_asmprintf(u, "repne ");
+ }
+
+ /* special instructions */
+ switch (u->mnemonic) {
+ case UD_Iretf:
+ ud_asmprintf(u, "lret ");
+ break;
+ case UD_Idb:
+ ud_asmprintf(u, ".byte 0x%x", u->operand[0].lval.ubyte);
+ return;
+ case UD_Ijmp:
+ case UD_Icall:
+ if (u->br_far) ud_asmprintf(u, "l");
+ if (u->operand[0].type == UD_OP_REG) {
+ star = 1;
+ }
+ ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
+ break;
+ case UD_Ibound:
+ case UD_Ienter:
+ if (u->operand[0].type != UD_NONE)
+ gen_operand(u, &u->operand[0]);
+ if (u->operand[1].type != UD_NONE) {
+ ud_asmprintf(u, ",");
+ gen_operand(u, &u->operand[1]);
+ }
+ return;
+ default:
+ ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
+ }
+
+ if (size == 8) {
+ ud_asmprintf(u, "b");
+ } else if (size == 16) {
+ ud_asmprintf(u, "w");
+ } else if (size == 64) {
+ ud_asmprintf(u, "q");
+ }
+
+ if (star) {
+ ud_asmprintf(u, " *");
+ } else {
+ ud_asmprintf(u, " ");
+ }
+
+ if (u->operand[3].type != UD_NONE) {
+ gen_operand(u, &u->operand[3]);
+ ud_asmprintf(u, ", ");
+ }
+ if (u->operand[2].type != UD_NONE) {
+ gen_operand(u, &u->operand[2]);
+ ud_asmprintf(u, ", ");
+ }
+ if (u->operand[1].type != UD_NONE) {
+ gen_operand(u, &u->operand[1]);
+ ud_asmprintf(u, ", ");
+ }
+ if (u->operand[0].type != UD_NONE) {
+ gen_operand(u, &u->operand[0]);
+ }
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/ext/opcache/jit/libudis86/syn-intel.c b/ext/opcache/jit/libudis86/syn-intel.c
new file mode 100644
index 0000000000..0664fea092
--- /dev/null
+++ b/ext/opcache/jit/libudis86/syn-intel.c
@@ -0,0 +1,224 @@
+/* udis86 - libudis86/syn-intel.c
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "types.h"
+#include "extern.h"
+#include "decode.h"
+#include "itab.h"
+#include "syn.h"
+#include "udint.h"
+
+/* -----------------------------------------------------------------------------
+ * opr_cast() - Prints an operand cast.
+ * -----------------------------------------------------------------------------
+ */
+static void
+opr_cast(struct ud* u, struct ud_operand* op)
+{
+ if (u->br_far) {
+ ud_asmprintf(u, "far ");
+ }
+ switch(op->size) {
+ case 8: ud_asmprintf(u, "byte " ); break;
+ case 16: ud_asmprintf(u, "word " ); break;
+ case 32: ud_asmprintf(u, "dword "); break;
+ case 64: ud_asmprintf(u, "qword "); break;
+ case 80: ud_asmprintf(u, "tword "); break;
+ case 128: ud_asmprintf(u, "oword "); break;
+ case 256: ud_asmprintf(u, "yword "); break;
+ default: break;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * gen_operand() - Generates assembly output for each operand.
+ * -----------------------------------------------------------------------------
+ */
+static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast)
+{
+ switch(op->type) {
+ case UD_OP_REG:
+ ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
+ break;
+
+ case UD_OP_MEM:
+ if (syn_cast) {
+ opr_cast(u, op);
+ }
+ ud_asmprintf(u, "[");
+ if (u->pfx_seg) {
+ ud_asmprintf(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
+ }
+ if (op->base) {
+ ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
+ }
+ if (op->index) {
+ ud_asmprintf(u, "%s%s", op->base != UD_NONE? "+" : "",
+ ud_reg_tab[op->index - UD_R_AL]);
+ if (op->scale) {
+ ud_asmprintf(u, "*%d", op->scale);
+ }
+ }
+ if (op->offset != 0) {
+ ud_syn_print_mem_disp(u, op, (op->base != UD_NONE ||
+ op->index != UD_NONE) ? 1 : 0);
+ }
+ ud_asmprintf(u, "]");
+ break;
+
+ case UD_OP_IMM:
+ ud_syn_print_imm(u, op);
+ break;
+
+
+ case UD_OP_JIMM:
+ ud_syn_print_addr(u, ud_syn_rel_target(u, op));
+ break;
+
+ case UD_OP_PTR:
+ switch (op->size) {
+ case 32:
+ ud_asmprintf(u, "word 0x%x:0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off & 0xFFFF);
+ break;
+ case 48:
+ ud_asmprintf(u, "dword 0x%x:0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off);
+ break;
+ }
+ break;
+
+ case UD_OP_CONST:
+ if (syn_cast) opr_cast(u, op);
+ ud_asmprintf(u, "%d", op->lval.udword);
+ break;
+
+ default: return;
+ }
+}
+
+/* =============================================================================
+ * translates to intel syntax
+ * =============================================================================
+ */
+extern void
+ud_translate_intel(struct ud* u)
+{
+ /* check if P_OSO prefix is used */
+ if (!P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
+ switch (u->dis_mode) {
+ case 16: ud_asmprintf(u, "o32 "); break;
+ case 32:
+ case 64: ud_asmprintf(u, "o16 "); break;
+ }
+ }
+
+ /* check if P_ASO prefix was used */
+ if (!P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
+ switch (u->dis_mode) {
+ case 16: ud_asmprintf(u, "a32 "); break;
+ case 32: ud_asmprintf(u, "a16 "); break;
+ case 64: ud_asmprintf(u, "a32 "); break;
+ }
+ }
+
+ if (u->pfx_seg &&
+ u->operand[0].type != UD_OP_MEM &&
+ u->operand[1].type != UD_OP_MEM ) {
+ ud_asmprintf(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]);
+ }
+
+ if (u->pfx_lock) {
+ ud_asmprintf(u, "lock ");
+ }
+ if (u->pfx_rep) {
+ ud_asmprintf(u, "rep ");
+ } else if (u->pfx_repe) {
+ ud_asmprintf(u, "repe ");
+ } else if (u->pfx_repne) {
+ ud_asmprintf(u, "repne ");
+ }
+
+ /* print the instruction mnemonic */
+ ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
+
+ if (u->operand[0].type != UD_NONE) {
+ int cast = 0;
+ ud_asmprintf(u, " ");
+ if (u->operand[0].type == UD_OP_MEM) {
+ if (u->operand[1].type == UD_OP_IMM ||
+ u->operand[1].type == UD_OP_CONST ||
+ u->operand[1].type == UD_NONE ||
+ (u->operand[0].size != u->operand[1].size)) {
+ cast = 1;
+ } else if (u->operand[1].type == UD_OP_REG &&
+ u->operand[1].base == UD_R_CL) {
+ switch (u->mnemonic) {
+ case UD_Ircl:
+ case UD_Irol:
+ case UD_Iror:
+ case UD_Ircr:
+ case UD_Ishl:
+ case UD_Ishr:
+ case UD_Isar:
+ cast = 1;
+ break;
+ default: break;
+ }
+ }
+ }
+ gen_operand(u, &u->operand[0], cast);
+ }
+
+ if (u->operand[1].type != UD_NONE) {
+ int cast = 0;
+ ud_asmprintf(u, ", ");
+ if (u->operand[1].type == UD_OP_MEM &&
+ u->operand[0].size != u->operand[1].size &&
+ !ud_opr_is_sreg(&u->operand[0])) {
+ cast = 1;
+ }
+ gen_operand(u, &u->operand[1], cast);
+ }
+
+ if (u->operand[2].type != UD_NONE) {
+ int cast = 0;
+ ud_asmprintf(u, ", ");
+ if (u->operand[2].type == UD_OP_MEM &&
+ u->operand[2].size != u->operand[1].size) {
+ cast = 1;
+ }
+ gen_operand(u, &u->operand[2], cast);
+ }
+
+ if (u->operand[3].type != UD_NONE) {
+ ud_asmprintf(u, ", ");
+ gen_operand(u, &u->operand[3], 0);
+ }
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/ext/opcache/jit/libudis86/syn.c b/ext/opcache/jit/libudis86/syn.c
new file mode 100644
index 0000000000..c7453d63b7
--- /dev/null
+++ b/ext/opcache/jit/libudis86/syn.c
@@ -0,0 +1,258 @@
+/* udis86 - libudis86/syn.c
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "types.h"
+#include "decode.h"
+#include "syn.h"
+#include "udint.h"
+
+/*
+ * Register Table - Order Matters (types.h)!
+ *
+ */
+const char* ud_reg_tab[] =
+{
+ "al", "cl", "dl", "bl",
+ "ah", "ch", "dh", "bh",
+ "spl", "bpl", "sil", "dil",
+ "r8b", "r9b", "r10b", "r11b",
+ "r12b", "r13b", "r14b", "r15b",
+
+ "ax", "cx", "dx", "bx",
+ "sp", "bp", "si", "di",
+ "r8w", "r9w", "r10w", "r11w",
+ "r12w", "r13w", "r14w", "r15w",
+
+ "eax", "ecx", "edx", "ebx",
+ "esp", "ebp", "esi", "edi",
+ "r8d", "r9d", "r10d", "r11d",
+ "r12d", "r13d", "r14d", "r15d",
+
+ "rax", "rcx", "rdx", "rbx",
+ "rsp", "rbp", "rsi", "rdi",
+ "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15",
+
+ "es", "cs", "ss", "ds",
+ "fs", "gs",
+
+ "cr0", "cr1", "cr2", "cr3",
+ "cr4", "cr5", "cr6", "cr7",
+ "cr8", "cr9", "cr10", "cr11",
+ "cr12", "cr13", "cr14", "cr15",
+
+ "dr0", "dr1", "dr2", "dr3",
+ "dr4", "dr5", "dr6", "dr7",
+ "dr8", "dr9", "dr10", "dr11",
+ "dr12", "dr13", "dr14", "dr15",
+
+ "mm0", "mm1", "mm2", "mm3",
+ "mm4", "mm5", "mm6", "mm7",
+
+ "st0", "st1", "st2", "st3",
+ "st4", "st5", "st6", "st7",
+
+ "xmm0", "xmm1", "xmm2", "xmm3",
+ "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11",
+ "xmm12", "xmm13", "xmm14", "xmm15",
+
+ "ymm0", "ymm1", "ymm2", "ymm3",
+ "ymm4", "ymm5", "ymm6", "ymm7",
+ "ymm8", "ymm9", "ymm10", "ymm11",
+ "ymm12", "ymm13", "ymm14", "ymm15",
+
+ "rip"
+};
+
+
+uint64_t
+ud_syn_rel_target(struct ud *u, struct ud_operand *opr)
+{
+#if 1
+ const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->adr_mode);
+#else
+ const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->opr_mode);
+#endif
+ switch (opr->size) {
+ case 8 : return (u->pc + opr->lval.sbyte) & trunc_mask;
+ case 16: return (u->pc + opr->lval.sword) & trunc_mask;
+ case 32: return (u->pc + opr->lval.sdword) & trunc_mask;
+ default: UD_ASSERT(!"invalid relative offset size.");
+ return 0ull;
+ }
+}
+
+
+/*
+ * asmprintf
+ * Printf style function for printing translated assembly
+ * output. Returns the number of characters written and
+ * moves the buffer pointer forward. On an overflow,
+ * returns a negative number and truncates the output.
+ */
+int
+ud_asmprintf(struct ud *u, const char *fmt, ...)
+{
+ int ret;
+ int avail;
+ va_list ap;
+ va_start(ap, fmt);
+ avail = u->asm_buf_size - u->asm_buf_fill - 1 /* nullchar */;
+ ret = vsnprintf((char*) u->asm_buf + u->asm_buf_fill, avail, fmt, ap);
+ if (ret < 0 || ret > avail) {
+ u->asm_buf_fill = u->asm_buf_size - 1;
+ } else {
+ u->asm_buf_fill += ret;
+ }
+ va_end(ap);
+ return ret;
+}
+
+
+void
+ud_syn_print_addr(struct ud *u, uint64_t addr)
+{
+ const char *name = NULL;
+ if (u->sym_resolver) {
+ int64_t offset = 0;
+ name = u->sym_resolver(u, addr, &offset);
+ if (name) {
+ if (offset) {
+ ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
+ } else {
+ ud_asmprintf(u, "%s", name);
+ }
+ return;
+ }
+ }
+ ud_asmprintf(u, "0x%" FMT64 "x", addr);
+}
+
+
+void
+ud_syn_print_imm(struct ud* u, const struct ud_operand *op)
+{
+ uint64_t v;
+ if (op->_oprcode == OP_sI && op->size != u->opr_mode) {
+ if (op->size == 8) {
+ v = (int64_t)op->lval.sbyte;
+ } else {
+ UD_ASSERT(op->size == 32);
+ v = (int64_t)op->lval.sdword;
+ }
+ if (u->opr_mode < 64) {
+ v = v & ((1ull << u->opr_mode) - 1ull);
+ }
+ } else {
+ switch (op->size) {
+ case 8 : v = op->lval.ubyte; break;
+ case 16: v = op->lval.uword; break;
+ case 32: v = op->lval.udword; break;
+ case 64: v = op->lval.uqword; break;
+ default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
+ }
+ }
+#if 1
+ if (u->sym_resolver) {
+ int64_t offset = 0;
+ const char *name = u->sym_resolver(u, v, &offset);
+ if (name) {
+ if (offset) {
+ ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
+ } else {
+ ud_asmprintf(u, "%s", name);
+ }
+ return;
+ }
+ }
+#endif
+ ud_asmprintf(u, "0x%" FMT64 "x", v);
+}
+
+
+void
+ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *op, int sign)
+{
+ UD_ASSERT(op->offset != 0);
+ if (op->base == UD_NONE && op->index == UD_NONE) {
+ uint64_t v;
+ UD_ASSERT(op->scale == UD_NONE && op->offset != 8);
+ /* unsigned mem-offset */
+ switch (op->offset) {
+ case 16: v = op->lval.uword; break;
+ case 32: v = op->lval.udword; break;
+ case 64: v = op->lval.uqword; break;
+ default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
+ }
+#if 1
+ if (u->sym_resolver) {
+ int64_t offset = 0;
+ const char *name = u->sym_resolver(u, v, &offset);
+ if (name) {
+ if (offset) {
+ ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
+ } else {
+ ud_asmprintf(u, "%s", name);
+ }
+ return;
+ }
+ }
+#endif
+ ud_asmprintf(u, "0x%" FMT64 "x", v);
+ } else {
+ int64_t v;
+ UD_ASSERT(op->offset != 64);
+ switch (op->offset) {
+ case 8 : v = op->lval.sbyte; break;
+ case 16: v = op->lval.sword; break;
+ case 32: v = op->lval.sdword; break;
+ default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
+ }
+#if 1
+ if (u->sym_resolver) {
+ int64_t offset = 0;
+ const char *name = u->sym_resolver(u, v, &offset);
+ if (name) {
+ if (offset) {
+ ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
+ } else {
+ ud_asmprintf(u, "%s", name);
+ }
+ return;
+ }
+ }
+#endif
+ if (v < 0) {
+ ud_asmprintf(u, "-0x%" FMT64 "x", -v);
+ } else if (v > 0) {
+ ud_asmprintf(u, "%s0x%" FMT64 "x", sign? "+" : "", v);
+ }
+ }
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/ext/opcache/jit/libudis86/syn.h b/ext/opcache/jit/libudis86/syn.h
new file mode 100644
index 0000000000..d3b1e3fe04
--- /dev/null
+++ b/ext/opcache/jit/libudis86/syn.h
@@ -0,0 +1,53 @@
+/* udis86 - libudis86/syn.h
+ *
+ * Copyright (c) 2002-2009
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_SYN_H
+#define UD_SYN_H
+
+#include "types.h"
+#ifndef __UD_STANDALONE__
+# include <stdarg.h>
+#endif /* __UD_STANDALONE__ */
+
+extern const char* ud_reg_tab[];
+
+uint64_t ud_syn_rel_target(struct ud*, struct ud_operand*);
+
+#ifdef __GNUC__
+int ud_asmprintf(struct ud *u, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+#else
+int ud_asmprintf(struct ud *u, const char *fmt, ...);
+#endif
+
+void ud_syn_print_addr(struct ud *u, uint64_t addr);
+void ud_syn_print_imm(struct ud* u, const struct ud_operand *op);
+void ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *, int sign);
+
+#endif /* UD_SYN_H */
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/ext/opcache/jit/libudis86/types.h b/ext/opcache/jit/libudis86/types.h
new file mode 100644
index 0000000000..69072ca480
--- /dev/null
+++ b/ext/opcache/jit/libudis86/types.h
@@ -0,0 +1,260 @@
+/* udis86 - libudis86/types.h
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_TYPES_H
+#define UD_TYPES_H
+
+#ifdef __KERNEL__
+ /*
+ * -D__KERNEL__ is automatically passed on the command line when
+ * building something as part of the Linux kernel. Assume standalone
+ * mode.
+ */
+# include <linux/kernel.h>
+# include <linux/string.h>
+# ifndef __UD_STANDALONE__
+# define __UD_STANDALONE__ 1
+# endif
+#endif /* __KERNEL__ */
+
+#if !defined(__UD_STANDALONE__)
+# include <stdint.h>
+# include <stdio.h>
+#endif
+
+/* gcc specific extensions */
+#ifdef __GNUC__
+# define UD_ATTR_PACKED __attribute__((packed))
+#else
+# define UD_ATTR_PACKED
+#endif /* UD_ATTR_PACKED */
+
+
+/* -----------------------------------------------------------------------------
+ * All possible "types" of objects in udis86. Order is Important!
+ * -----------------------------------------------------------------------------
+ */
+enum ud_type
+{
+ UD_NONE,
+
+ /* 8 bit GPRs */
+ UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL,
+ UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH,
+ UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL,
+ UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B,
+ UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B,
+
+ /* 16 bit GPRs */
+ UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX,
+ UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI,
+ UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W,
+ UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W,
+
+ /* 32 bit GPRs */
+ UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX,
+ UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI,
+ UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D,
+ UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D,
+
+ /* 64 bit GPRs */
+ UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX,
+ UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI,
+ UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11,
+ UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15,
+
+ /* segment registers */
+ UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS,
+ UD_R_FS, UD_R_GS,
+
+ /* control registers*/
+ UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3,
+ UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7,
+ UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11,
+ UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15,
+
+ /* debug registers */
+ UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3,
+ UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7,
+ UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11,
+ UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15,
+
+ /* mmx registers */
+ UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3,
+ UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7,
+
+ /* x87 registers */
+ UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3,
+ UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7,
+
+ /* extended multimedia registers */
+ UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3,
+ UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7,
+ UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11,
+ UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15,
+
+ /* 256B multimedia registers */
+ UD_R_YMM0, UD_R_YMM1, UD_R_YMM2, UD_R_YMM3,
+ UD_R_YMM4, UD_R_YMM5, UD_R_YMM6, UD_R_YMM7,
+ UD_R_YMM8, UD_R_YMM9, UD_R_YMM10, UD_R_YMM11,
+ UD_R_YMM12, UD_R_YMM13, UD_R_YMM14, UD_R_YMM15,
+
+ UD_R_RIP,
+
+ /* Operand Types */
+ UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM,
+ UD_OP_JIMM, UD_OP_CONST
+};
+
+#include "itab.h"
+
+union ud_lval {
+ int8_t sbyte;
+ uint8_t ubyte;
+ int16_t sword;
+ uint16_t uword;
+ int32_t sdword;
+ uint32_t udword;
+ int64_t sqword;
+ uint64_t uqword;
+ struct {
+ uint16_t seg;
+ uint32_t off;
+ } ptr;
+};
+
+/* -----------------------------------------------------------------------------
+ * struct ud_operand - Disassembled instruction Operand.
+ * -----------------------------------------------------------------------------
+ */
+struct ud_operand {
+ enum ud_type type;
+ uint16_t size;
+ enum ud_type base;
+ enum ud_type index;
+ uint8_t scale;
+ uint8_t offset;
+ union ud_lval lval;
+ /*
+ * internal use only
+ */
+ uint64_t _legacy; /* this will be removed in 1.8 */
+ uint8_t _oprcode;
+};
+
+/* -----------------------------------------------------------------------------
+ * struct ud - The udis86 object.
+ * -----------------------------------------------------------------------------
+ */
+struct ud
+{
+ /*
+ * input buffering
+ */
+ int (*inp_hook) (struct ud*);
+#ifndef __UD_STANDALONE__
+ FILE* inp_file;
+#endif
+ const uint8_t* inp_buf;
+ size_t inp_buf_size;
+ size_t inp_buf_index;
+ uint8_t inp_curr;
+ size_t inp_ctr;
+ uint8_t inp_sess[64];
+ int inp_end;
+ int inp_peek;
+
+ void (*translator)(struct ud*);
+ uint64_t insn_offset;
+ char insn_hexcode[64];
+
+ /*
+ * Assembly output buffer
+ */
+ char *asm_buf;
+ size_t asm_buf_size;
+ size_t asm_buf_fill;
+ char asm_buf_int[128];
+
+ /*
+ * Symbol resolver for use in the translation phase.
+ */
+ const char* (*sym_resolver)(struct ud*, uint64_t addr, int64_t *offset);
+
+ uint8_t dis_mode;
+ uint64_t pc;
+ uint8_t vendor;
+ enum ud_mnemonic_code mnemonic;
+ struct ud_operand operand[4];
+ uint8_t error;
+ uint8_t _rex;
+ uint8_t pfx_rex;
+ uint8_t pfx_seg;
+ uint8_t pfx_opr;
+ uint8_t pfx_adr;
+ uint8_t pfx_lock;
+ uint8_t pfx_str;
+ uint8_t pfx_rep;
+ uint8_t pfx_repe;
+ uint8_t pfx_repne;
+ uint8_t opr_mode;
+ uint8_t adr_mode;
+ uint8_t br_far;
+ uint8_t br_near;
+ uint8_t have_modrm;
+ uint8_t modrm;
+ uint8_t modrm_offset;
+ uint8_t vex_op;
+ uint8_t vex_b1;
+ uint8_t vex_b2;
+ uint8_t primary_opcode;
+ void * user_opaque_data;
+ struct ud_itab_entry * itab_entry;
+ struct ud_lookup_table_list_entry *le;
+};
+
+/* -----------------------------------------------------------------------------
+ * Type-definitions
+ * -----------------------------------------------------------------------------
+ */
+typedef enum ud_type ud_type_t;
+typedef enum ud_mnemonic_code ud_mnemonic_code_t;
+
+typedef struct ud ud_t;
+typedef struct ud_operand ud_operand_t;
+
+#define UD_SYN_INTEL ud_translate_intel
+#define UD_SYN_ATT ud_translate_att
+#define UD_EOI (-1)
+#define UD_INP_CACHE_SZ 32
+#define UD_VENDOR_AMD 0
+#define UD_VENDOR_INTEL 1
+#define UD_VENDOR_ANY 2
+
+#endif
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/ext/opcache/jit/libudis86/udint.h b/ext/opcache/jit/libudis86/udint.h
new file mode 100644
index 0000000000..734f0eaa82
--- /dev/null
+++ b/ext/opcache/jit/libudis86/udint.h
@@ -0,0 +1,99 @@
+/* udis86 - libudis86/udint.h -- definitions for internal use only
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _UDINT_H_
+#define _UDINT_H_
+
+#include "types.h"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined(UD_DEBUG) && HAVE_ASSERT_H
+# include <assert.h>
+# define UD_ASSERT(_x) assert(_x)
+#else
+# define UD_ASSERT(_x)
+#endif /* !HAVE_ASSERT_H */
+
+#if defined(UD_DEBUG)
+ #define UDERR(u, msg) \
+ do { \
+ (u)->error = 1; \
+ fprintf(stderr, "decode-error: %s:%d: %s", \
+ __FILE__, __LINE__, (msg)); \
+ } while (0)
+#else
+ #define UDERR(u, m) \
+ do { \
+ (u)->error = 1; \
+ } while (0)
+#endif /* !LOGERR */
+
+#define UD_RETURN_ON_ERROR(u) \
+ do { \
+ if ((u)->error != 0) { \
+ return (u)->error; \
+ } \
+ } while (0)
+
+#define UD_RETURN_WITH_ERROR(u, m) \
+ do { \
+ UDERR(u, m); \
+ return (u)->error; \
+ } while (0)
+
+#ifndef __UD_STANDALONE__
+# define UD_NON_STANDALONE(x) x
+#else
+# define UD_NON_STANDALONE(x)
+#endif
+
+/* printf formatting int64 specifier */
+#ifdef FMT64
+# undef FMT64
+#endif
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+# define FMT64 "I64"
+#else
+# if defined(__APPLE__)
+# define FMT64 "ll"
+# elif defined(__amd64__) || defined(__x86_64__)
+# define FMT64 "l"
+# else
+# define FMT64 "ll"
+# endif /* !x64 */
+#endif
+
+/* define an inline macro */
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+# define UD_INLINE __inline /* MS Visual Studio requires __inline
+ instead of inline for C code */
+#else
+# define UD_INLINE inline
+#endif
+
+#endif /* _UDINT_H_ */
diff --git a/ext/opcache/jit/libudis86/udis86.c b/ext/opcache/jit/libudis86/udis86.c
new file mode 100644
index 0000000000..0e00729feb
--- /dev/null
+++ b/ext/opcache/jit/libudis86/udis86.c
@@ -0,0 +1,458 @@
+/* udis86 - libudis86/udis86.c
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "udint.h"
+#include "extern.h"
+#include "decode.h"
+
+#if !defined(__UD_STANDALONE__)
+# if HAVE_STRING_H
+# include <string.h>
+# endif
+#endif /* !__UD_STANDALONE__ */
+
+static void ud_inp_init(struct ud *u);
+
+/* =============================================================================
+ * ud_init
+ * Initializes ud_t object.
+ * =============================================================================
+ */
+extern void
+ud_init(struct ud* u)
+{
+ memset((void*)u, 0, sizeof(struct ud));
+ ud_set_mode(u, 16);
+ u->mnemonic = UD_Iinvalid;
+ ud_set_pc(u, 0);
+#ifndef __UD_STANDALONE__
+ ud_set_input_file(u, stdin);
+#endif /* __UD_STANDALONE__ */
+
+ ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
+}
+
+
+/* =============================================================================
+ * ud_disassemble
+ * Disassembles one instruction and returns the number of
+ * bytes disassembled. A zero means end of disassembly.
+ * =============================================================================
+ */
+extern unsigned int
+ud_disassemble(struct ud* u)
+{
+ int len;
+ if (u->inp_end) {
+ return 0;
+ }
+ if ((len = ud_decode(u)) > 0) {
+ if (u->translator != NULL) {
+ u->asm_buf[0] = '\0';
+ u->translator(u);
+ }
+ }
+ return len;
+}
+
+
+/* =============================================================================
+ * ud_set_mode() - Set Disassemly Mode.
+ * =============================================================================
+ */
+extern void
+ud_set_mode(struct ud* u, uint8_t m)
+{
+ switch(m) {
+ case 16:
+ case 32:
+ case 64: u->dis_mode = m ; return;
+ default: u->dis_mode = 16; return;
+ }
+}
+
+/* =============================================================================
+ * ud_set_vendor() - Set vendor.
+ * =============================================================================
+ */
+extern void
+ud_set_vendor(struct ud* u, unsigned v)
+{
+ switch(v) {
+ case UD_VENDOR_INTEL:
+ u->vendor = v;
+ break;
+ case UD_VENDOR_ANY:
+ u->vendor = v;
+ break;
+ default:
+ u->vendor = UD_VENDOR_AMD;
+ }
+}
+
+/* =============================================================================
+ * ud_set_pc() - Sets code origin.
+ * =============================================================================
+ */
+extern void
+ud_set_pc(struct ud* u, uint64_t o)
+{
+ u->pc = o;
+}
+
+/* =============================================================================
+ * ud_set_syntax() - Sets the output syntax.
+ * =============================================================================
+ */
+extern void
+ud_set_syntax(struct ud* u, void (*t)(struct ud*))
+{
+ u->translator = t;
+}
+
+/* =============================================================================
+ * ud_insn() - returns the disassembled instruction
+ * =============================================================================
+ */
+const char*
+ud_insn_asm(const struct ud* u)
+{
+ return u->asm_buf;
+}
+
+/* =============================================================================
+ * ud_insn_offset() - Returns the offset.
+ * =============================================================================
+ */
+uint64_t
+ud_insn_off(const struct ud* u)
+{
+ return u->insn_offset;
+}
+
+
+/* =============================================================================
+ * ud_insn_hex() - Returns hex form of disassembled instruction.
+ * =============================================================================
+ */
+const char*
+ud_insn_hex(struct ud* u)
+{
+ u->insn_hexcode[0] = 0;
+ if (!u->error) {
+ unsigned int i;
+ const unsigned char *src_ptr = ud_insn_ptr(u);
+ char* src_hex;
+ src_hex = (char*) u->insn_hexcode;
+ /* for each byte used to decode instruction */
+ for (i = 0; i < ud_insn_len(u) && i < sizeof(u->insn_hexcode) / 2;
+ ++i, ++src_ptr) {
+ sprintf(src_hex, "%02x", *src_ptr & 0xFF);
+ src_hex += 2;
+ }
+ }
+ return u->insn_hexcode;
+}
+
+
+/* =============================================================================
+ * ud_insn_ptr
+ * Returns a pointer to buffer containing the bytes that were
+ * disassembled.
+ * =============================================================================
+ */
+extern const uint8_t*
+ud_insn_ptr(const struct ud* u)
+{
+ return (u->inp_buf == NULL) ?
+ u->inp_sess : u->inp_buf + (u->inp_buf_index - u->inp_ctr);
+}
+
+
+/* =============================================================================
+ * ud_insn_len
+ * Returns the count of bytes disassembled.
+ * =============================================================================
+ */
+extern unsigned int
+ud_insn_len(const struct ud* u)
+{
+ return u->inp_ctr;
+}
+
+
+/* =============================================================================
+ * ud_insn_get_opr
+ * Return the operand struct representing the nth operand of
+ * the currently disassembled instruction. Returns NULL if
+ * there's no such operand.
+ * =============================================================================
+ */
+const struct ud_operand*
+ud_insn_opr(const struct ud *u, unsigned int n)
+{
+ if (n > 3 || u->operand[n].type == UD_NONE) {
+ return NULL;
+ } else {
+ return &u->operand[n];
+ }
+}
+
+
+/* =============================================================================
+ * ud_opr_is_sreg
+ * Returns non-zero if the given operand is of a segment register type.
+ * =============================================================================
+ */
+int
+ud_opr_is_sreg(const struct ud_operand *opr)
+{
+ return opr->type == UD_OP_REG &&
+ opr->base >= UD_R_ES &&
+ opr->base <= UD_R_GS;
+}
+
+
+/* =============================================================================
+ * ud_opr_is_sreg
+ * Returns non-zero if the given operand is of a general purpose
+ * register type.
+ * =============================================================================
+ */
+int
+ud_opr_is_gpr(const struct ud_operand *opr)
+{
+ return opr->type == UD_OP_REG &&
+ opr->base >= UD_R_AL &&
+ opr->base <= UD_R_R15;
+}
+
+
+/* =============================================================================
+ * ud_set_user_opaque_data
+ * ud_get_user_opaque_data
+ * Get/set user opaqute data pointer
+ * =============================================================================
+ */
+void
+ud_set_user_opaque_data(struct ud * u, void* opaque)
+{
+ u->user_opaque_data = opaque;
+}
+
+void*
+ud_get_user_opaque_data(const struct ud *u)
+{
+ return u->user_opaque_data;
+}
+
+
+/* =============================================================================
+ * ud_set_asm_buffer
+ * Allow the user to set an assembler output buffer. If `buf` is NULL,
+ * we switch back to the internal buffer.
+ * =============================================================================
+ */
+void
+ud_set_asm_buffer(struct ud *u, char *buf, size_t size)
+{
+ if (buf == NULL) {
+ ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
+ } else {
+ u->asm_buf = buf;
+ u->asm_buf_size = size;
+ }
+}
+
+
+/* =============================================================================
+ * ud_set_sym_resolver
+ * Set symbol resolver for relative targets used in the translation
+ * phase.
+ *
+ * The resolver is a function that takes a uint64_t address and returns a
+ * symbolic name for the that address. The function also takes a second
+ * argument pointing to an integer that the client can optionally set to a
+ * non-zero value for offsetted targets. (symbol+offset) The function may
+ * also return NULL, in which case the translator only prints the target
+ * address.
+ *
+ * The function pointer maybe NULL which resets symbol resolution.
+ * =============================================================================
+ */
+void
+ud_set_sym_resolver(struct ud *u, const char* (*resolver)(struct ud*,
+ uint64_t addr,
+ int64_t *offset))
+{
+ u->sym_resolver = resolver;
+}
+
+
+/* =============================================================================
+ * ud_insn_mnemonic
+ * Return the current instruction mnemonic.
+ * =============================================================================
+ */
+enum ud_mnemonic_code
+ud_insn_mnemonic(const struct ud *u)
+{
+ return u->mnemonic;
+}
+
+
+/* =============================================================================
+ * ud_lookup_mnemonic
+ * Looks up mnemonic code in the mnemonic string table.
+ * Returns NULL if the mnemonic code is invalid.
+ * =============================================================================
+ */
+const char*
+ud_lookup_mnemonic(enum ud_mnemonic_code c)
+{
+ if (c < UD_MAX_MNEMONIC_CODE) {
+ return ud_mnemonics_str[c];
+ } else {
+ return "???";
+ }
+}
+
+
+/*
+ * ud_inp_init
+ * Initializes the input system.
+ */
+static void
+ud_inp_init(struct ud *u)
+{
+ u->inp_hook = NULL;
+ u->inp_buf = NULL;
+ u->inp_buf_size = 0;
+ u->inp_buf_index = 0;
+ u->inp_curr = 0;
+ u->inp_ctr = 0;
+ u->inp_end = 0;
+ u->inp_peek = UD_EOI;
+ UD_NON_STANDALONE(u->inp_file = NULL);
+}
+
+
+/* =============================================================================
+ * ud_inp_set_hook
+ * Sets input hook.
+ * =============================================================================
+ */
+void
+ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*))
+{
+ ud_inp_init(u);
+ u->inp_hook = hook;
+}
+
+/* =============================================================================
+ * ud_inp_set_buffer
+ * Set buffer as input.
+ * =============================================================================
+ */
+void
+ud_set_input_buffer(register struct ud* u, const uint8_t* buf, size_t len)
+{
+ ud_inp_init(u);
+ u->inp_buf = buf;
+ u->inp_buf_size = len;
+ u->inp_buf_index = 0;
+}
+
+
+#ifndef __UD_STANDALONE__
+/* =============================================================================
+ * ud_input_set_file
+ * Set FILE as input.
+ * =============================================================================
+ */
+static int
+inp_file_hook(struct ud* u)
+{
+ return fgetc(u->inp_file);
+}
+
+void
+ud_set_input_file(register struct ud* u, FILE* f)
+{
+ ud_inp_init(u);
+ u->inp_hook = inp_file_hook;
+ u->inp_file = f;
+}
+#endif /* __UD_STANDALONE__ */
+
+
+/* =============================================================================
+ * ud_input_skip
+ * Skip n input bytes.
+ * ============================================================================
+ */
+void
+ud_input_skip(struct ud* u, size_t n)
+{
+ if (u->inp_end) {
+ return;
+ }
+ if (u->inp_buf == NULL) {
+ while (n--) {
+ int c = u->inp_hook(u);
+ if (c == UD_EOI) {
+ goto eoi;
+ }
+ }
+ return;
+ } else {
+ if (n > u->inp_buf_size ||
+ u->inp_buf_index > u->inp_buf_size - n) {
+ u->inp_buf_index = u->inp_buf_size;
+ goto eoi;
+ }
+ u->inp_buf_index += n;
+ return;
+ }
+eoi:
+ u->inp_end = 1;
+ UDERR(u, "cannot skip, eoi received\b");
+ return;
+}
+
+
+/* =============================================================================
+ * ud_input_end
+ * Returns non-zero on end-of-input.
+ * =============================================================================
+ */
+int
+ud_input_end(const struct ud *u)
+{
+ return u->inp_end;
+}
+
+/* vim:set ts=2 sw=2 expandtab */
diff --git a/ext/opcache/jit/vtune/ittnotify_config.h b/ext/opcache/jit/vtune/ittnotify_config.h
new file mode 100644
index 0000000000..fc3a476cdd
--- /dev/null
+++ b/ext/opcache/jit/vtune/ittnotify_config.h
@@ -0,0 +1,596 @@
+/* <copyright>
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</copyright> */
+#ifndef _ITTNOTIFY_CONFIG_H_
+#define _ITTNOTIFY_CONFIG_H_
+
+/** @cond exclude_from_documentation */
+#ifndef ITT_OS_WIN
+# define ITT_OS_WIN 1
+#endif /* ITT_OS_WIN */
+
+#ifndef ITT_OS_LINUX
+# define ITT_OS_LINUX 2
+#endif /* ITT_OS_LINUX */
+
+#ifndef ITT_OS_MAC
+# define ITT_OS_MAC 3
+#endif /* ITT_OS_MAC */
+
+#ifndef ITT_OS_FREEBSD
+# define ITT_OS_FREEBSD 4
+#endif /* ITT_OS_FREEBSD */
+
+#ifndef ITT_OS
+# if defined WIN32 || defined _WIN32
+# define ITT_OS ITT_OS_WIN
+# elif defined( __APPLE__ ) && defined( __MACH__ )
+# define ITT_OS ITT_OS_MAC
+# elif defined( __FreeBSD__ )
+# define ITT_OS ITT_OS_FREEBSD
+# else
+# define ITT_OS ITT_OS_LINUX
+# endif
+#endif /* ITT_OS */
+
+#ifndef ITT_PLATFORM_WIN
+# define ITT_PLATFORM_WIN 1
+#endif /* ITT_PLATFORM_WIN */
+
+#ifndef ITT_PLATFORM_POSIX
+# define ITT_PLATFORM_POSIX 2
+#endif /* ITT_PLATFORM_POSIX */
+
+#ifndef ITT_PLATFORM_MAC
+# define ITT_PLATFORM_MAC 3
+#endif /* ITT_PLATFORM_MAC */
+
+#ifndef ITT_PLATFORM_FREEBSD
+# define ITT_PLATFORM_FREEBSD 4
+#endif /* ITT_PLATFORM_FREEBSD */
+
+#ifndef ITT_PLATFORM
+# if ITT_OS==ITT_OS_WIN
+# define ITT_PLATFORM ITT_PLATFORM_WIN
+# elif ITT_OS==ITT_OS_MAC
+# define ITT_PLATFORM ITT_PLATFORM_MAC
+# elif ITT_OS==ITT_OS_FREEBSD
+# define ITT_PLATFORM ITT_PLATFORM_FREEBSD
+# else
+# define ITT_PLATFORM ITT_PLATFORM_POSIX
+# endif
+#endif /* ITT_PLATFORM */
+
+#if defined(_UNICODE) && !defined(UNICODE)
+#define UNICODE
+#endif
+
+#include <stddef.h>
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <tchar.h>
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <stdint.h>
+#if defined(UNICODE) || defined(_UNICODE)
+#include <wchar.h>
+#endif /* UNICODE || _UNICODE */
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#ifndef ITTAPI_CDECL
+# if ITT_PLATFORM==ITT_PLATFORM_WIN
+# define ITTAPI_CDECL __cdecl
+# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+# if defined _M_IX86 || defined __i386__
+# define ITTAPI_CDECL __attribute__ ((cdecl))
+# else /* _M_IX86 || __i386__ */
+# define ITTAPI_CDECL /* actual only on x86 platform */
+# endif /* _M_IX86 || __i386__ */
+# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#endif /* ITTAPI_CDECL */
+
+#ifndef STDCALL
+# if ITT_PLATFORM==ITT_PLATFORM_WIN
+# define STDCALL __stdcall
+# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+# if defined _M_IX86 || defined __i386__
+# define STDCALL __attribute__ ((stdcall))
+# else /* _M_IX86 || __i386__ */
+# define STDCALL /* supported only on x86 platform */
+# endif /* _M_IX86 || __i386__ */
+# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#endif /* STDCALL */
+
+#define ITTAPI ITTAPI_CDECL
+#define LIBITTAPI ITTAPI_CDECL
+
+/* TODO: Temporary for compatibility! */
+#define ITTAPI_CALL ITTAPI_CDECL
+#define LIBITTAPI_CALL ITTAPI_CDECL
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+/* use __forceinline (VC++ specific) */
+#define ITT_INLINE __forceinline
+#define ITT_INLINE_ATTRIBUTE /* nothing */
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+/*
+ * Generally, functions are not inlined unless optimization is specified.
+ * For functions declared inline, this attribute inlines the function even
+ * if no optimization level was specified.
+ */
+#ifdef __STRICT_ANSI__
+#define ITT_INLINE static
+#define ITT_INLINE_ATTRIBUTE __attribute__((unused))
+#else /* __STRICT_ANSI__ */
+#define ITT_INLINE static inline
+#define ITT_INLINE_ATTRIBUTE __attribute__((always_inline, unused))
+#endif /* __STRICT_ANSI__ */
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+/** @endcond */
+
+#ifndef ITT_ARCH_IA32
+# define ITT_ARCH_IA32 1
+#endif /* ITT_ARCH_IA32 */
+
+#ifndef ITT_ARCH_IA32E
+# define ITT_ARCH_IA32E 2
+#endif /* ITT_ARCH_IA32E */
+
+#ifndef ITT_ARCH_ARM
+# define ITT_ARCH_ARM 4
+#endif /* ITT_ARCH_ARM */
+
+#ifndef ITT_ARCH_PPC64
+# define ITT_ARCH_PPC64 5
+#endif /* ITT_ARCH_PPC64 */
+
+#ifndef ITT_ARCH
+# if defined _M_IX86 || defined __i386__
+# define ITT_ARCH ITT_ARCH_IA32
+# elif defined _M_X64 || defined _M_AMD64 || defined __x86_64__
+# define ITT_ARCH ITT_ARCH_IA32E
+# elif defined _M_IA64 || defined __ia64__
+# define ITT_ARCH ITT_ARCH_IA64
+# elif defined _M_ARM || defined __arm__
+# define ITT_ARCH ITT_ARCH_ARM
+# elif defined __powerpc64__
+# define ITT_ARCH ITT_ARCH_PPC64
+# endif
+#endif
+
+#ifdef __cplusplus
+# define ITT_EXTERN_C extern "C"
+# define ITT_EXTERN_C_BEGIN extern "C" {
+# define ITT_EXTERN_C_END }
+#else
+# define ITT_EXTERN_C /* nothing */
+# define ITT_EXTERN_C_BEGIN /* nothing */
+# define ITT_EXTERN_C_END /* nothing */
+#endif /* __cplusplus */
+
+#define ITT_TO_STR_AUX(x) #x
+#define ITT_TO_STR(x) ITT_TO_STR_AUX(x)
+
+#define __ITT_BUILD_ASSERT(expr, suffix) do { \
+ static char __itt_build_check_##suffix[(expr) ? 1 : -1]; \
+ __itt_build_check_##suffix[0] = 0; \
+} while(0)
+#define _ITT_BUILD_ASSERT(expr, suffix) __ITT_BUILD_ASSERT((expr), suffix)
+#define ITT_BUILD_ASSERT(expr) _ITT_BUILD_ASSERT((expr), __LINE__)
+
+#define ITT_MAGIC { 0xED, 0xAB, 0xAB, 0xEC, 0x0D, 0xEE, 0xDA, 0x30 }
+
+/* Replace with snapshot date YYYYMMDD for promotion build. */
+#define API_VERSION_BUILD 20151119
+
+#ifndef API_VERSION_NUM
+#define API_VERSION_NUM 0.0.0
+#endif /* API_VERSION_NUM */
+
+#define API_VERSION "ITT-API-Version " ITT_TO_STR(API_VERSION_NUM) \
+ " (" ITT_TO_STR(API_VERSION_BUILD) ")"
+
+/* OS communication functions */
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <windows.h>
+typedef HMODULE lib_t;
+typedef DWORD TIDT;
+typedef CRITICAL_SECTION mutex_t;
+#define MUTEX_INITIALIZER { 0 }
+#define strong_alias(name, aliasname) /* empty for Windows */
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <dlfcn.h>
+#if defined(UNICODE) || defined(_UNICODE)
+#include <wchar.h>
+#endif /* UNICODE */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1 /* need for PTHREAD_MUTEX_RECURSIVE */
+#endif /* _GNU_SOURCE */
+#ifndef __USE_UNIX98
+#define __USE_UNIX98 1 /* need for PTHREAD_MUTEX_RECURSIVE, on SLES11.1 with gcc 4.3.4 wherein pthread.h missing dependency on __USE_XOPEN2K8 */
+#endif /*__USE_UNIX98*/
+#include <pthread.h>
+typedef void* lib_t;
+typedef pthread_t TIDT;
+typedef pthread_mutex_t mutex_t;
+#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+#define _strong_alias(name, aliasname) \
+ extern __typeof (name) aliasname __attribute__ ((alias (#name)));
+#define strong_alias(name, aliasname) _strong_alias(name, aliasname)
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#define __itt_get_proc(lib, name) GetProcAddress(lib, name)
+#define __itt_mutex_init(mutex) InitializeCriticalSection(mutex)
+#define __itt_mutex_lock(mutex) EnterCriticalSection(mutex)
+#define __itt_mutex_unlock(mutex) LeaveCriticalSection(mutex)
+#define __itt_load_lib(name) LoadLibraryA(name)
+#define __itt_unload_lib(handle) FreeLibrary(handle)
+#define __itt_system_error() (int)GetLastError()
+#define __itt_fstrcmp(s1, s2) lstrcmpA(s1, s2)
+#define __itt_fstrnlen(s, l) strnlen_s(s, l)
+#define __itt_fstrcpyn(s1, b, s2, l) strncpy_s(s1, b, s2, l)
+#define __itt_fstrdup(s) _strdup(s)
+#define __itt_thread_id() GetCurrentThreadId()
+#define __itt_thread_yield() SwitchToThread()
+#ifndef ITT_SIMPLE_INIT
+ITT_INLINE long
+__itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE long __itt_interlocked_increment(volatile long* ptr)
+{
+ return InterlockedIncrement(ptr);
+}
+#endif /* ITT_SIMPLE_INIT */
+#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */
+#define __itt_get_proc(lib, name) dlsym(lib, name)
+#define __itt_mutex_init(mutex) {\
+ pthread_mutexattr_t mutex_attr; \
+ int error_code = pthread_mutexattr_init(&mutex_attr); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutexattr_init", \
+ error_code); \
+ error_code = pthread_mutexattr_settype(&mutex_attr, \
+ PTHREAD_MUTEX_RECURSIVE); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutexattr_settype", \
+ error_code); \
+ error_code = pthread_mutex_init(mutex, &mutex_attr); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutex_init", \
+ error_code); \
+ error_code = pthread_mutexattr_destroy(&mutex_attr); \
+ if (error_code) \
+ __itt_report_error(__itt_error_system, "pthread_mutexattr_destroy", \
+ error_code); \
+}
+#define __itt_mutex_lock(mutex) pthread_mutex_lock(mutex)
+#define __itt_mutex_unlock(mutex) pthread_mutex_unlock(mutex)
+#define __itt_load_lib(name) dlopen(name, RTLD_LAZY)
+#define __itt_unload_lib(handle) dlclose(handle)
+#define __itt_system_error() errno
+#define __itt_fstrcmp(s1, s2) strcmp(s1, s2)
+
+/* makes customer code define safe APIs for SDL_STRNLEN_S and SDL_STRNCPY_S */
+#ifdef SDL_STRNLEN_S
+#define __itt_fstrnlen(s, l) SDL_STRNLEN_S(s, l)
+#else
+#define __itt_fstrnlen(s, l) strlen(s)
+#endif /* SDL_STRNLEN_S */
+#ifdef SDL_STRNCPY_S
+#define __itt_fstrcpyn(s1, b, s2, l) SDL_STRNCPY_S(s1, b, s2, l)
+#else
+#define __itt_fstrcpyn(s1, b, s2, l) strncpy(s1, s2, l)
+#endif /* SDL_STRNCPY_S */
+
+#define __itt_fstrdup(s) strdup(s)
+#define __itt_thread_id() pthread_self()
+#define __itt_thread_yield() sched_yield()
+#if ITT_ARCH==ITT_ARCH_IA64
+#ifdef __INTEL_COMPILER
+#define __TBB_machine_fetchadd4(addr, val) __fetchadd4_acq((void *)addr, val)
+#else /* __INTEL_COMPILER */
+/* TODO: Add Support for not Intel compilers for IA-64 architecture */
+#endif /* __INTEL_COMPILER */
+#elif ITT_ARCH==ITT_ARCH_IA32 || ITT_ARCH==ITT_ARCH_IA32E /* ITT_ARCH!=ITT_ARCH_IA64 */
+ITT_INLINE long
+__TBB_machine_fetchadd4(volatile void* ptr, long addend) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE long __TBB_machine_fetchadd4(volatile void* ptr, long addend)
+{
+ long result;
+ __asm__ __volatile__("lock\nxadd %0,%1"
+ : "=r"(result),"=m"(*(int*)ptr)
+ : "0"(addend), "m"(*(int*)ptr)
+ : "memory");
+ return result;
+}
+#elif ITT_ARCH==ITT_ARCH_ARM || ITT_ARCH==ITT_ARCH_PPC64
+#define __TBB_machine_fetchadd4(addr, val) __sync_fetch_and_add(addr, val)
+#endif /* ITT_ARCH==ITT_ARCH_IA64 */
+#ifndef ITT_SIMPLE_INIT
+ITT_INLINE long
+__itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE;
+ITT_INLINE long __itt_interlocked_increment(volatile long* ptr)
+{
+ return __TBB_machine_fetchadd4(ptr, 1) + 1L;
+}
+#endif /* ITT_SIMPLE_INIT */
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+typedef enum {
+ __itt_collection_normal = 0,
+ __itt_collection_paused = 1
+} __itt_collection_state;
+
+typedef enum {
+ __itt_thread_normal = 0,
+ __itt_thread_ignored = 1
+} __itt_thread_state;
+
+#pragma pack(push, 8)
+
+typedef struct ___itt_thread_info
+{
+ const char* nameA; /*!< Copy of original name in ASCII. */
+#if defined(UNICODE) || defined(_UNICODE)
+ const wchar_t* nameW; /*!< Copy of original name in UNICODE. */
+#else /* UNICODE || _UNICODE */
+ void* nameW;
+#endif /* UNICODE || _UNICODE */
+ TIDT tid;
+ __itt_thread_state state; /*!< Thread state (paused or normal) */
+ int extra1; /*!< Reserved to the runtime */
+ void* extra2; /*!< Reserved to the runtime */
+ struct ___itt_thread_info* next;
+} __itt_thread_info;
+
+#include "ittnotify_types.h" /* For __itt_group_id definition */
+
+typedef struct ___itt_api_info_20101001
+{
+ const char* name;
+ void** func_ptr;
+ void* init_func;
+ __itt_group_id group;
+} __itt_api_info_20101001;
+
+typedef struct ___itt_api_info
+{
+ const char* name;
+ void** func_ptr;
+ void* init_func;
+ void* null_func;
+ __itt_group_id group;
+} __itt_api_info;
+
+typedef struct __itt_counter_info
+{
+ const char* nameA; /*!< Copy of original name in ASCII. */
+#if defined(UNICODE) || defined(_UNICODE)
+ const wchar_t* nameW; /*!< Copy of original name in UNICODE. */
+#else /* UNICODE || _UNICODE */
+ void* nameW;
+#endif /* UNICODE || _UNICODE */
+ const char* domainA; /*!< Copy of original name in ASCII. */
+#if defined(UNICODE) || defined(_UNICODE)
+ const wchar_t* domainW; /*!< Copy of original name in UNICODE. */
+#else /* UNICODE || _UNICODE */
+ void* domainW;
+#endif /* UNICODE || _UNICODE */
+ int type;
+ long index;
+ int extra1; /*!< Reserved to the runtime */
+ void* extra2; /*!< Reserved to the runtime */
+ struct __itt_counter_info* next;
+} __itt_counter_info_t;
+
+struct ___itt_domain;
+struct ___itt_string_handle;
+
+typedef struct ___itt_global
+{
+ unsigned char magic[8];
+ unsigned long version_major;
+ unsigned long version_minor;
+ unsigned long version_build;
+ volatile long api_initialized;
+ volatile long mutex_initialized;
+ volatile long atomic_counter;
+ mutex_t mutex;
+ lib_t lib;
+ void* error_handler;
+ const char** dll_path_ptr;
+ __itt_api_info* api_list_ptr;
+ struct ___itt_global* next;
+ /* Joinable structures below */
+ __itt_thread_info* thread_list;
+ struct ___itt_domain* domain_list;
+ struct ___itt_string_handle* string_list;
+ __itt_collection_state state;
+ __itt_counter_info_t* counter_list;
+} __itt_global;
+
+#pragma pack(pop)
+
+#define NEW_THREAD_INFO_W(gptr,h,h_tail,t,s,n) { \
+ h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
+ if (h != NULL) { \
+ h->tid = t; \
+ h->nameA = NULL; \
+ h->nameW = n ? _wcsdup(n) : NULL; \
+ h->state = s; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->thread_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_THREAD_INFO_A(gptr,h,h_tail,t,s,n) { \
+ h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \
+ if (h != NULL) { \
+ h->tid = t; \
+ h->nameA = n ? __itt_fstrdup(n) : NULL; \
+ h->nameW = NULL; \
+ h->state = s; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->thread_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_DOMAIN_W(gptr,h,h_tail,name) { \
+ h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
+ if (h != NULL) { \
+ h->flags = 1; /* domain is enabled by default */ \
+ h->nameA = NULL; \
+ h->nameW = name ? _wcsdup(name) : NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->domain_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_DOMAIN_A(gptr,h,h_tail,name) { \
+ h = (__itt_domain*)malloc(sizeof(__itt_domain)); \
+ if (h != NULL) { \
+ h->flags = 1; /* domain is enabled by default */ \
+ h->nameA = name ? __itt_fstrdup(name) : NULL; \
+ h->nameW = NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->domain_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_STRING_HANDLE_W(gptr,h,h_tail,name) { \
+ h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
+ if (h != NULL) { \
+ h->strA = NULL; \
+ h->strW = name ? _wcsdup(name) : NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->string_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_STRING_HANDLE_A(gptr,h,h_tail,name) { \
+ h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \
+ if (h != NULL) { \
+ h->strA = name ? __itt_fstrdup(name) : NULL; \
+ h->strW = NULL; \
+ h->extra1 = 0; /* reserved */ \
+ h->extra2 = NULL; /* reserved */ \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->string_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_COUNTER_W(gptr,h,h_tail,name,domain,type) { \
+ h = (__itt_counter_info_t*)malloc(sizeof(__itt_counter_info_t)); \
+ if (h != NULL) { \
+ h->nameA = NULL; \
+ h->nameW = name ? _wcsdup(name) : NULL; \
+ h->domainA = NULL; \
+ h->domainW = name ? _wcsdup(domain) : NULL; \
+ h->type = type; \
+ h->index = 0; \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->counter_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#define NEW_COUNTER_A(gptr,h,h_tail,name,domain,type) { \
+ h = (__itt_counter_info_t*)malloc(sizeof(__itt_counter_info_t)); \
+ if (h != NULL) { \
+ h->nameA = name ? __itt_fstrdup(name) : NULL; \
+ h->nameW = NULL; \
+ h->domainA = domain ? __itt_fstrdup(domain) : NULL; \
+ h->domainW = NULL; \
+ h->type = type; \
+ h->index = 0; \
+ h->next = NULL; \
+ if (h_tail == NULL) \
+ (gptr)->counter_list = h; \
+ else \
+ h_tail->next = h; \
+ } \
+}
+
+#endif /* _ITTNOTIFY_CONFIG_H_ */
diff --git a/ext/opcache/jit/vtune/ittnotify_types.h b/ext/opcache/jit/vtune/ittnotify_types.h
new file mode 100644
index 0000000000..e10250bd63
--- /dev/null
+++ b/ext/opcache/jit/vtune/ittnotify_types.h
@@ -0,0 +1,115 @@
+/* <copyright>
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</copyright> */
+
+#ifndef _ITTNOTIFY_TYPES_H_
+#define _ITTNOTIFY_TYPES_H_
+
+typedef enum ___itt_group_id
+{
+ __itt_group_none = 0,
+ __itt_group_legacy = 1<<0,
+ __itt_group_control = 1<<1,
+ __itt_group_thread = 1<<2,
+ __itt_group_mark = 1<<3,
+ __itt_group_sync = 1<<4,
+ __itt_group_fsync = 1<<5,
+ __itt_group_jit = 1<<6,
+ __itt_group_model = 1<<7,
+ __itt_group_splitter_min = 1<<7,
+ __itt_group_counter = 1<<8,
+ __itt_group_frame = 1<<9,
+ __itt_group_stitch = 1<<10,
+ __itt_group_heap = 1<<11,
+ __itt_group_splitter_max = 1<<12,
+ __itt_group_structure = 1<<12,
+ __itt_group_suppress = 1<<13,
+ __itt_group_arrays = 1<<14,
+ __itt_group_all = -1
+} __itt_group_id;
+
+#pragma pack(push, 8)
+
+typedef struct ___itt_group_list
+{
+ __itt_group_id id;
+ const char* name;
+} __itt_group_list;
+
+#pragma pack(pop)
+
+#define ITT_GROUP_LIST(varname) \
+ static __itt_group_list varname[] = { \
+ { __itt_group_all, "all" }, \
+ { __itt_group_control, "control" }, \
+ { __itt_group_thread, "thread" }, \
+ { __itt_group_mark, "mark" }, \
+ { __itt_group_sync, "sync" }, \
+ { __itt_group_fsync, "fsync" }, \
+ { __itt_group_jit, "jit" }, \
+ { __itt_group_model, "model" }, \
+ { __itt_group_counter, "counter" }, \
+ { __itt_group_frame, "frame" }, \
+ { __itt_group_stitch, "stitch" }, \
+ { __itt_group_heap, "heap" }, \
+ { __itt_group_structure, "structure" }, \
+ { __itt_group_suppress, "suppress" }, \
+ { __itt_group_arrays, "arrays" }, \
+ { __itt_group_none, NULL } \
+ }
+
+#endif /* _ITTNOTIFY_TYPES_H_ */
diff --git a/ext/opcache/jit/vtune/jitprofiling.c b/ext/opcache/jit/vtune/jitprofiling.c
new file mode 100644
index 0000000000..86efe047c4
--- /dev/null
+++ b/ext/opcache/jit/vtune/jitprofiling.c
@@ -0,0 +1,312 @@
+/* <copyright>
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</copyright> */
+
+#include "ittnotify_config.h"
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#include <windows.h>
+#pragma optimize("", off)
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+#include <stdlib.h>
+
+#include "jitprofiling.h"
+
+static const char rcsid[] = "\n@(#) $Revision: 463960 $\n";
+
+#define DLL_ENVIRONMENT_VAR "VS_PROFILER"
+
+#ifndef NEW_DLL_ENVIRONMENT_VAR
+#if ITT_ARCH==ITT_ARCH_IA32
+#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32"
+#else
+#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64"
+#endif
+#endif /* NEW_DLL_ENVIRONMENT_VAR */
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+#define DEFAULT_DLLNAME "JitPI.dll"
+HINSTANCE m_libHandle = NULL;
+#elif ITT_PLATFORM==ITT_PLATFORM_MAC
+#define DEFAULT_DLLNAME "libJitPI.dylib"
+void* m_libHandle = NULL;
+#else
+#define DEFAULT_DLLNAME "libJitPI.so"
+void* m_libHandle = NULL;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+/* default location of JIT profiling agent on Android */
+#define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so"
+
+/* the function pointers */
+typedef unsigned int(JITAPI *TPInitialize)(void);
+static TPInitialize FUNC_Initialize=NULL;
+
+typedef unsigned int(JITAPI *TPNotify)(unsigned int, void*);
+static TPNotify FUNC_NotifyEvent=NULL;
+
+static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING;
+
+/* end collector dll part. */
+
+/* loadiJIT_Funcs() : this function is called just in the beginning
+ * and is responsible to load the functions from BistroJavaCollector.dll
+ * result:
+ * on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1
+ * on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0
+ */
+static int loadiJIT_Funcs(void);
+
+/* global representing whether the collector can't be loaded */
+static int iJIT_DLL_is_missing = 0;
+
+ITT_EXTERN_C int JITAPI
+iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData)
+{
+ int ReturnValue;
+
+ /* initialization part - the collector has not been loaded yet. */
+ if (!FUNC_NotifyEvent)
+ {
+ if (iJIT_DLL_is_missing)
+ return 0;
+
+ if (!loadiJIT_Funcs())
+ return 0;
+ }
+
+ if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED ||
+ event_type == iJVM_EVENT_TYPE_METHOD_UPDATE)
+ {
+ if (((piJIT_Method_Load)EventSpecificData)->method_id == 0)
+ return 0;
+ }
+ else if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2)
+ {
+ if (((piJIT_Method_Load_V2)EventSpecificData)->method_id == 0)
+ return 0;
+ }
+ else if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3)
+ {
+ if (((piJIT_Method_Load_V3)EventSpecificData)->method_id == 0)
+ return 0;
+ }
+ else if (event_type == iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED)
+ {
+ if (((piJIT_Method_Inline_Load)EventSpecificData)->method_id == 0 ||
+ ((piJIT_Method_Inline_Load)EventSpecificData)->parent_method_id == 0)
+ return 0;
+ }
+
+ ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData);
+
+ return ReturnValue;
+}
+
+ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive()
+{
+ if (!iJIT_DLL_is_missing)
+ {
+ loadiJIT_Funcs();
+ }
+
+ return executionMode;
+}
+
+/* This function loads the collector dll and the relevant functions.
+ * on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1
+ * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0
+ */
+static int loadiJIT_Funcs()
+{
+ static int bDllWasLoaded = 0;
+ char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ DWORD dNameLength = 0;
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+ if(bDllWasLoaded)
+ {
+ /* dll was already loaded, no need to do it for the second time */
+ return 1;
+ }
+
+ /* Assumes that the DLL will not be found */
+ iJIT_DLL_is_missing = 1;
+ FUNC_NotifyEvent = NULL;
+
+ if (m_libHandle)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ FreeLibrary(m_libHandle);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ dlclose(m_libHandle);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ m_libHandle = NULL;
+ }
+
+ /* Try to get the dll name from the environment */
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0);
+ if (dNameLength)
+ {
+ DWORD envret = 0;
+ dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
+ if(dllName != NULL)
+ {
+ envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR,
+ dllName, dNameLength);
+ if (envret)
+ {
+ /* Try to load the dll from the PATH... */
+ m_libHandle = LoadLibraryExA(dllName,
+ NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ }
+ free(dllName);
+ }
+ } else {
+ /* Try to use old VS_PROFILER variable */
+ dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0);
+ if (dNameLength)
+ {
+ DWORD envret = 0;
+ dllName = (char*)malloc(sizeof(char) * (dNameLength + 1));
+ if(dllName != NULL)
+ {
+ envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR,
+ dllName, dNameLength);
+ if (envret)
+ {
+ /* Try to load the dll from the PATH... */
+ m_libHandle = LoadLibraryA(dllName);
+ }
+ free(dllName);
+ }
+ }
+ }
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ dllName = getenv(NEW_DLL_ENVIRONMENT_VAR);
+ if (!dllName)
+ dllName = getenv(DLL_ENVIRONMENT_VAR);
+#if defined(__ANDROID__) || defined(ANDROID)
+ if (!dllName)
+ dllName = ANDROID_JIT_AGENT_PATH;
+#endif
+ if (dllName)
+ {
+ /* Try to load the dll from the PATH... */
+ m_libHandle = dlopen(dllName, RTLD_LAZY);
+ }
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+
+ if (!m_libHandle)
+ {
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ m_libHandle = LoadLibraryA(DEFAULT_DLLNAME);
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY);
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ }
+
+ /* if the dll wasn't loaded - exit. */
+ if (!m_libHandle)
+ {
+ iJIT_DLL_is_missing = 1; /* don't try to initialize
+ * JIT agent the second time
+ */
+ return 0;
+ }
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent");
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ FUNC_NotifyEvent = (TPNotify)dlsym(m_libHandle, "NotifyEvent");
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ if (!FUNC_NotifyEvent)
+ {
+ FUNC_Initialize = NULL;
+ return 0;
+ }
+
+#if ITT_PLATFORM==ITT_PLATFORM_WIN
+ FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize");
+#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ FUNC_Initialize = (TPInitialize)dlsym(m_libHandle, "Initialize");
+#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */
+ if (!FUNC_Initialize)
+ {
+ FUNC_NotifyEvent = NULL;
+ return 0;
+ }
+
+ executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize();
+
+ bDllWasLoaded = 1;
+ iJIT_DLL_is_missing = 0; /* DLL is ok. */
+
+ return 1;
+}
+
+ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID()
+{
+ static unsigned int methodID = 1;
+
+ if (methodID == 0)
+ return 0; /* ERROR : this is not a valid value */
+
+ return methodID++;
+}
diff --git a/ext/opcache/jit/vtune/jitprofiling.h b/ext/opcache/jit/vtune/jitprofiling.h
new file mode 100644
index 0000000000..3e166c04d4
--- /dev/null
+++ b/ext/opcache/jit/vtune/jitprofiling.h
@@ -0,0 +1,694 @@
+/* <copyright>
+ This file is provided under a dual BSD/GPLv2 license. When using or
+ redistributing this file, you may do so under either license.
+
+ GPL LICENSE SUMMARY
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
+
+ BSD LICENSE
+
+ Copyright (c) 2005-2014 Intel Corporation. All rights reserved.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</copyright> */
+
+#ifndef __JITPROFILING_H__
+#define __JITPROFILING_H__
+
+/**
+ * @brief JIT Profiling APIs
+ *
+ * The JIT Profiling API is used to report information about just-in-time
+ * generated code that can be used by performance tools. The user inserts
+ * calls in the code generator to report information before JIT-compiled
+ * code goes to execution. This information is collected at runtime and used
+ * by tools like Intel(R) VTune(TM) Amplifier to display performance metrics
+ * associated with JIT-compiled code.
+ *
+ * These APIs can be used to\n
+ * - **Profile trace-based and method-based JIT-compiled
+ * code**. Some examples of environments that you can profile with these APIs:
+ * dynamic JIT compilation of JavaScript code traces, JIT execution in OpenCL(TM)
+ * software technology, Java/.NET managed execution environments, and custom
+ * ISV JIT engines.
+ * @code
+ * #include <jitprofiling.h>
+ *
+ * if (iJIT_IsProfilingActive != iJIT_SAMPLING_ON) {
+ * return;
+ * }
+ *
+ * iJIT_Method_Load jmethod = {0};
+ * jmethod.method_id = iJIT_GetNewMethodID();
+ * jmethod.method_name = "method_name";
+ * jmethod.class_file_name = "class_name";
+ * jmethod.source_file_name = "source_file_name";
+ * jmethod.method_load_address = code_addr;
+ * jmethod.method_size = code_size;
+ *
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod);
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL);
+ * @endcode
+ *
+ * * Expected behavior:
+ * * If any iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event overwrites an
+ * already reported method, then such a method becomes invalid and its
+ * memory region is treated as unloaded. VTune Amplifier displays the metrics
+ * collected by the method until it is overwritten.
+ * * If supplied line number information contains multiple source lines for
+ * the same assembly instruction (code location), then VTune Amplifier picks up
+ * the first line number.
+ * * Dynamically generated code can be associated with a module name.
+ * Use the iJIT_Method_Load_V2 structure.\n
+ * Clarification of some cases:
+ * * If you register a function with the same method ID multiple times,
+ * specifying different module names, then the VTune Amplifier picks up
+ * the module name registered first. If you want to distinguish the same
+ * function between different JIT engines, supply different method IDs for
+ * each function. Other symbolic information (for example, source file)
+ * can be identical.
+ *
+ * - **Analyze split functions** (multiple joint or disjoint code regions
+ * belonging to the same function) **including re-JIT**
+ * with potential overlapping of code regions in time, which is common in
+ * resource-limited environments.
+ * @code
+ * #include <jitprofiling.h>
+ *
+ * unsigned int method_id = iJIT_GetNewMethodID();
+ *
+ * iJIT_Method_Load a = {0};
+ * a.method_id = method_id;
+ * a.method_load_address = 0x100;
+ * a.method_size = 0x20;
+ *
+ * iJIT_Method_Load b = {0};
+ * b.method_id = method_id;
+ * b.method_load_address = 0x200;
+ * b.method_size = 0x30;
+ *
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a);
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&b);
+ * @endcode
+ *
+ * * Expected behaviour:
+ * * If a iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event overwrites an
+ * already reported method, then such a method becomes invalid and
+ * its memory region is treated as unloaded.
+ * * All code regions reported with the same method ID are considered as
+ * belonging to the same method. Symbolic information (method name,
+ * source file name) will be taken from the first notification, and all
+ * subsequent notifications with the same method ID will be processed
+ * only for line number table information. So, the VTune Amplifier will map
+ * samples to a source line using the line number table from the current
+ * notification while taking the source file name from the very first one.\n
+ * Clarification of some cases:\n
+ * * If you register a second code region with a different source file
+ * name and the same method ID, then this information will be saved and
+ * will not be considered as an extension of the first code region, but
+ * VTune Amplifier will use the source file of the first code region and map
+ * performance metrics incorrectly.
+ * * If you register a second code region with the same source file as
+ * for the first region and the same method ID, then the source file will be
+ * discarded but VTune Amplifier will map metrics to the source file correctly.
+ * * If you register a second code region with a null source file and
+ * the same method ID, then provided line number info will be associated
+ * with the source file of the first code region.
+ *
+ * - **Explore inline functions** including multi-level hierarchy of
+ * nested inline methods which shows how performance metrics are distributed through them.
+ * @code
+ * #include <jitprofiling.h>
+ *
+ * // method_id parent_id
+ * // [-- c --] 3000 2000
+ * // [---- d -----] 2001 1000
+ * // [---- b ----] 2000 1000
+ * // [------------ a ----------------] 1000 n/a
+ *
+ * iJIT_Method_Load a = {0};
+ * a.method_id = 1000;
+ *
+ * iJIT_Method_Inline_Load b = {0};
+ * b.method_id = 2000;
+ * b.parent_method_id = 1000;
+ *
+ * iJIT_Method_Inline_Load c = {0};
+ * c.method_id = 3000;
+ * c.parent_method_id = 2000;
+ *
+ * iJIT_Method_Inline_Load d = {0};
+ * d.method_id = 2001;
+ * d.parent_method_id = 1000;
+ *
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a);
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&b);
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&c);
+ * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&d);
+ * @endcode
+ *
+ * * Requirements:
+ * * Each inline (iJIT_Method_Inline_Load) method should be associated
+ * with two method IDs: one for itself; one for its immediate parent.
+ * * Address regions of inline methods of the same parent method cannot
+ * overlap each other.
+ * * Execution of the parent method must not be started until it and all
+ * its inline methods are reported.
+ * * Expected behaviour:
+ * * In case of nested inline methods an order of
+ * iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED events is not important.
+ * * If any event overwrites either inline method or top parent method,
+ * then the parent, including inline methods, becomes invalid and its memory
+ * region is treated as unloaded.
+ *
+ * **Life time of allocated data**\n
+ * The client sends an event notification to the agent with event-specific
+ * data, which is a structure. The pointers in the structure refer to memory
+ * allocated by the client, which responsible for releasing it. The pointers are
+ * used by the iJIT_NotifyEvent method to copy client's data in a trace file,
+ * and they are not used after the iJIT_NotifyEvent method returns.
+ */
+
+/**
+ * @defgroup jitapi JIT Profiling
+ * @ingroup internal
+ * @{
+ */
+
+/**
+ * @brief Enumerator for the types of notifications
+ */
+typedef enum iJIT_jvm_event
+{
+ iJVM_EVENT_TYPE_SHUTDOWN = 2, /**<\brief Send this to shutdown the agent.
+ * Use NULL for event data. */
+
+ iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED = 13, /**<\brief Send when dynamic code is
+ * JIT compiled and loaded into
+ * memory by the JIT engine, but
+ * before the code is executed.
+ * Use iJIT_Method_Load as event
+ * data. */
+/** @cond exclude_from_documentation */
+ iJVM_EVENT_TYPE_METHOD_UNLOAD_START, /**<\brief Send when compiled dynamic
+ * code is being unloaded from memory.
+ * Use iJIT_Method_Load as event data.*/
+/** @endcond */
+
+ iJVM_EVENT_TYPE_METHOD_UPDATE, /**<\brief Send to provide new content for
+ * a previously reported dynamic code.
+ * The previous content will be invalidated
+ * starting from the time of the notification.
+ * Use iJIT_Method_Load as event data but
+ * required fields are following:
+ * - method_id identify the code to update.
+ * - method_load_address specify start address
+ * within identified code range
+ * where update should be started.
+ * - method_size specify length of updated code
+ * range. */
+
+
+ iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, /**<\brief Send when an inline dynamic
+ * code is JIT compiled and loaded
+ * into memory by the JIT engine,
+ * but before the parent code region
+ * starts executing.
+ * Use iJIT_Method_Inline_Load as event data.*/
+
+/** @cond exclude_from_documentation */
+ iJVM_EVENT_TYPE_METHOD_UPDATE_V2,
+/** @endcond */
+
+ iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2 = 21, /**<\brief Send when a dynamic code is
+ * JIT compiled and loaded into
+ * memory by the JIT engine, but
+ * before the code is executed.
+ * Use iJIT_Method_Load_V2 as event data. */
+
+ iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3 /**<\brief Send when a dynamic code is
+ * JIT compiled and loaded into
+ * memory by the JIT engine, but
+ * before the code is executed.
+ * Use iJIT_Method_Load_V3 as event data. */
+} iJIT_JVM_EVENT;
+
+/**
+ * @brief Enumerator for the agent's mode
+ */
+typedef enum _iJIT_IsProfilingActiveFlags
+{
+ iJIT_NOTHING_RUNNING = 0x0000, /**<\brief The agent is not running;
+ * iJIT_NotifyEvent calls will
+ * not be processed. */
+ iJIT_SAMPLING_ON = 0x0001, /**<\brief The agent is running and
+ * ready to process notifications. */
+} iJIT_IsProfilingActiveFlags;
+
+/**
+ * @brief Description of a single entry in the line number information of a code region.
+ * @details A table of line number entries gives information about how the reported code region
+ * is mapped to source file.
+ * Intel(R) VTune(TM) Amplifier uses line number information to attribute
+ * the samples (virtual address) to a line number. \n
+ * It is acceptable to report different code addresses for the same source line:
+ * @code
+ * Offset LineNumber
+ * 1 2
+ * 12 4
+ * 15 2
+ * 18 1
+ * 21 30
+ *
+ * VTune Amplifier constructs the following table using the client data
+ *
+ * Code subrange Line number
+ * 0-1 2
+ * 1-12 4
+ * 12-15 2
+ * 15-18 1
+ * 18-21 30
+ * @endcode
+ */
+typedef struct _LineNumberInfo
+{
+ unsigned int Offset; /**<\brief Offset from the begining of the code region. */
+ unsigned int LineNumber; /**<\brief Matching source line number offset (from beginning of source file). */
+
+} *pLineNumberInfo, LineNumberInfo;
+
+/**
+ * @brief Enumerator for the code architecture.
+ */
+typedef enum _iJIT_CodeArchitecture
+{
+ iJIT_CA_NATIVE = 0, /**<\brief Native to the process architecture that is calling it. */
+
+ iJIT_CA_32, /**<\brief 32-bit machine code. */
+
+ iJIT_CA_64 /**<\brief 64-bit machine code. */
+
+} iJIT_CodeArchitecture;
+
+#pragma pack(push, 8)
+
+/**
+ * @brief Description of a JIT-compiled method
+ * @details When you use the iJIT_Method_Load structure to describe
+ * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED
+ * as an event type to report it.
+ */
+typedef struct _iJIT_Method_Load
+{
+ unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
+ * You must either use the API function
+ * iJIT_GetNewMethodID to get a valid and unique
+ * method ID, or else manage ID uniqueness
+ * and correct range by yourself.\n
+ * You must use the same method ID for all code
+ * regions of the same method, otherwise different
+ * method IDs specify different methods. */
+
+ char* method_name; /**<\brief The name of the method. It can be optionally
+ * prefixed with its class name and appended with
+ * its complete signature. Can't be NULL. */
+
+ void* method_load_address; /**<\brief The start virtual address of the method code
+ * region. If NULL, data provided with
+ * event are not accepted. */
+
+ unsigned int method_size; /**<\brief The code size of the method in memory.
+ * If 0, then data provided with the event are not
+ * accepted. */
+
+ unsigned int line_number_size; /**<\brief The number of entries in the line number
+ * table.0 if none. */
+
+ pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
+ * array. Can be NULL if
+ * line_number_size is 0. See
+ * LineNumberInfo Structure for a
+ * description of a single entry in
+ * the line number info array */
+
+ unsigned int class_id; /**<\brief This field is obsolete. */
+
+ char* class_file_name; /**<\brief Class name. Can be NULL.*/
+
+ char* source_file_name; /**<\brief Source file name. Can be NULL.*/
+
+} *piJIT_Method_Load, iJIT_Method_Load;
+
+/**
+ * @brief Description of a JIT-compiled method
+ * @details When you use the iJIT_Method_Load_V2 structure to describe
+ * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2
+ * as an event type to report it.
+ */
+typedef struct _iJIT_Method_Load_V2
+{
+ unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
+ * You must either use the API function
+ * iJIT_GetNewMethodID to get a valid and unique
+ * method ID, or else manage ID uniqueness
+ * and correct range by yourself.\n
+ * You must use the same method ID for all code
+ * regions of the same method, otherwise different
+ * method IDs specify different methods. */
+
+ char* method_name; /**<\brief The name of the method. It can be optionally
+ * prefixed with its class name and appended with
+ * its complete signature. Can't be NULL. */
+
+ void* method_load_address; /**<\brief The start virtual address of the method code
+ * region. If NULL, then data provided with the
+ * event are not accepted. */
+
+ unsigned int method_size; /**<\brief The code size of the method in memory.
+ * If 0, then data provided with the event are not
+ * accepted. */
+
+ unsigned int line_number_size; /**<\brief The number of entries in the line number
+ * table. 0 if none. */
+
+ pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
+ * array. Can be NULL if
+ * line_number_size is 0. See
+ * LineNumberInfo Structure for a
+ * description of a single entry in
+ * the line number info array. */
+
+ char* class_file_name; /**<\brief Class name. Can be NULL. */
+
+ char* source_file_name; /**<\brief Source file name. Can be NULL. */
+
+ char* module_name; /**<\brief Module name. Can be NULL.
+ The module name can be useful for distinguishing among
+ different JIT engines. VTune Amplifier will display
+ reported methods grouped by specific module. */
+
+} *piJIT_Method_Load_V2, iJIT_Method_Load_V2;
+
+/**
+ * @brief Description of a JIT-compiled method
+ * @details The iJIT_Method_Load_V3 structure is the same as iJIT_Method_Load_V2
+ * with a newly introduced 'arch' field that specifies architecture of the code region.
+ * When you use the iJIT_Method_Load_V3 structure to describe
+ * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3
+ * as an event type to report it.
+ */
+typedef struct _iJIT_Method_Load_V3
+{
+ unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
+ * You must either use the API function
+ * iJIT_GetNewMethodID to get a valid and unique
+ * method ID, or manage ID uniqueness
+ * and correct range by yourself.\n
+ * You must use the same method ID for all code
+ * regions of the same method, otherwise they are
+ * treated as regions of different methods. */
+
+ char* method_name; /**<\brief The name of the method. It can be optionally
+ * prefixed with its class name and appended with
+ * its complete signature. Cannot be NULL. */
+
+ void* method_load_address; /**<\brief The start virtual address of the method code
+ * region. If NULL, then data provided with the
+ * event are not accepted. */
+
+ unsigned int method_size; /**<\brief The code size of the method in memory.
+ * If 0, then data provided with the event are not
+ * accepted. */
+
+ unsigned int line_number_size; /**<\brief The number of entries in the line number
+ * table. 0 if none. */
+
+ pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
+ * array. Can be NULL if
+ * line_number_size is 0. See
+ * LineNumberInfo Structure for a
+ * description of a single entry in
+ * the line number info array. */
+
+ char* class_file_name; /**<\brief Class name. Can be NULL. */
+
+ char* source_file_name; /**<\brief Source file name. Can be NULL. */
+
+ char* module_name; /**<\brief Module name. Can be NULL.
+ * The module name can be useful for distinguishing among
+ * different JIT engines. VTune Amplifier will display
+ * reported methods grouped by specific module. */
+
+ iJIT_CodeArchitecture module_arch; /**<\brief Architecture of the method's code region.
+ * By default, it is the same as the process
+ * architecture that is calling it.
+ * For example, you can use it if your 32-bit JIT
+ * engine generates 64-bit code.
+ *
+ * If JIT engine reports both 32-bit and 64-bit types
+ * of methods then VTune Amplifier splits the methods
+ * with the same module name but with different
+ * architectures in two different modules. VTune Amplifier
+ * modifies the original name provided with a 64-bit method
+ * version by ending it with '(64)' */
+
+} *piJIT_Method_Load_V3, iJIT_Method_Load_V3;
+
+/**
+ * @brief Description of an inline JIT-compiled method
+ * @details When you use the_iJIT_Method_Inline_Load structure to describe
+ * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED
+ * as an event type to report it.
+ */
+typedef struct _iJIT_Method_Inline_Load
+{
+ unsigned int method_id; /**<\brief Unique method ID. Cannot be 0.
+ * You must either use the API function
+ * iJIT_GetNewMethodID to get a valid and unique
+ * method ID, or else manage ID uniqueness
+ * and correct range by yourself. */
+
+ unsigned int parent_method_id; /**<\brief Unique immediate parent's method ID.
+ * Cannot be 0.
+ * You must either use the API function
+ * iJIT_GetNewMethodID to get a valid and unique
+ * method ID, or else manage ID uniqueness
+ * and correct range by yourself. */
+
+ char* method_name; /**<\brief The name of the method. It can be optionally
+ * prefixed with its class name and appended with
+ * its complete signature. Can't be NULL. */
+
+ void* method_load_address; /** <\brief The virtual address on which the method
+ * is inlined. If NULL, then data provided with
+ * the event are not accepted. */
+
+ unsigned int method_size; /**<\brief The code size of the method in memory.
+ * If 0, then data provided with the event are not
+ * accepted. */
+
+ unsigned int line_number_size; /**<\brief The number of entries in the line number
+ * table. 0 if none. */
+
+ pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info
+ * array. Can be NULL if
+ * line_number_size is 0. See
+ * LineNumberInfo Structure for a
+ * description of a single entry in
+ * the line number info array */
+
+ char* class_file_name; /**<\brief Class name. Can be NULL.*/
+
+ char* source_file_name; /**<\brief Source file name. Can be NULL.*/
+
+} *piJIT_Method_Inline_Load, iJIT_Method_Inline_Load;
+
+/** @cond exclude_from_documentation */
+/**
+ * @brief Description of a segment type
+ * @details Use the segment type to specify a type of data supplied
+ * with the iJVM_EVENT_TYPE_METHOD_UPDATE_V2 event to be applied to
+ * a certain code trace.
+ */
+typedef enum _iJIT_SegmentType
+{
+ iJIT_CT_UNKNOWN = 0,
+
+ iJIT_CT_CODE, /**<\brief Executable code. */
+
+ iJIT_CT_DATA, /**<\brief Data (not executable code).
+ * VTune Amplifier uses the format string
+ * (see iJIT_Method_Update) to represent
+ * this data in the VTune Amplifier GUI */
+
+ iJIT_CT_KEEP, /**<\brief Use the previous markup for the trace.
+ * Can be used for the following
+ * iJVM_EVENT_TYPE_METHOD_UPDATE_V2 events,
+ * if the type of the previously reported segment
+ * type is the same. */
+ iJIT_CT_EOF
+} iJIT_SegmentType;
+
+/**
+ * @brief Description of a dynamic update of the content within JIT-compiled method
+ * @details The JIT engine may generate the methods that are updated at runtime
+ * partially by mixed (data + executable code) content. When you use the iJIT_Method_Update
+ * structure to describe the update of the content within a JIT-compiled method,
+ * use iJVM_EVENT_TYPE_METHOD_UPDATE_V2 as an event type to report it.
+ *
+ * On the first Update event, VTune Amplifier copies the original code range reported by
+ * the iJVM_EVENT_TYPE_METHOD_LOAD event, then modifies it with the supplied bytes and
+ * adds the modified range to the original method. For next update events, VTune Amplifier
+ * does the same but it uses the latest modified version of a code region for update.
+ * Eventually, VTune Amplifier GUI displays multiple code ranges for the method reported by
+ * the iJVM_EVENT_TYPE_METHOD_LOAD event.
+ * Notes:
+ * - Multiple update events with different types for the same trace are allowed
+ * but they must be reported for the same code ranges.
+ * Example,
+ * @code
+ * [-- data---] Allowed
+ * [-- code --] Allowed
+ * [code] Ignored
+ * [-- data---] Allowed
+ * [-- code --] Allowed
+ * [------------ trace ---------]
+ * @endcode
+ * - The types of previously reported events can be changed but they must be reported
+ * for the same code ranges.
+ * Example,
+ * @code
+ * [-- data---] Allowed
+ * [-- code --] Allowed
+ * [-- data---] Allowed
+ * [-- code --] Allowed
+ * [------------ trace ---------]
+ * @endcode
+ */
+
+typedef struct _iJIT_Method_Update
+{
+ void* load_address; /**<\brief Start address of the update within a method */
+
+ unsigned int size; /**<\brief The update size */
+
+ iJIT_SegmentType type; /**<\brief Type of the update */
+
+ const char* data_format; /**<\brief C string that contains a format string
+ * that follows the same specifications as format in printf.
+ * The format string is used for iJIT_CT_CODE only
+ * and cannot be NULL.
+ * Format can be changed on the fly. */
+} *piJIT_Method_Update, iJIT_Method_Update;
+
+/** @endcond */
+
+#pragma pack(pop)
+
+/** @cond exclude_from_documentation */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef JITAPI_CDECL
+# if defined WIN32 || defined _WIN32
+# define JITAPI_CDECL __cdecl
+# else /* defined WIN32 || defined _WIN32 */
+# if defined _M_IX86 || defined __i386__
+# define JITAPI_CDECL __attribute__ ((cdecl))
+# else /* _M_IX86 || __i386__ */
+# define JITAPI_CDECL /* actual only on x86_64 platform */
+# endif /* _M_IX86 || __i386__ */
+# endif /* defined WIN32 || defined _WIN32 */
+#endif /* JITAPI_CDECL */
+
+#define JITAPI JITAPI_CDECL
+/** @endcond */
+
+/**
+ * @brief Generates a new unique method ID.
+ *
+ * You must use this API to obtain unique and valid method IDs for methods or
+ * traces reported to the agent if you don't have your own mechanism to generate
+ * unique method IDs.
+ *
+ * @return a new unique method ID. When out of unique method IDs, this API
+ * returns 0, which is not an accepted value.
+ */
+unsigned int JITAPI iJIT_GetNewMethodID(void);
+
+/**
+ * @brief Returns the current mode of the agent.
+ *
+ * @return iJIT_SAMPLING_ON, indicating that agent is running, or
+ * iJIT_NOTHING_RUNNING if no agent is running.
+ */
+iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void);
+
+/**
+ * @brief Reports infomation about JIT-compiled code to the agent.
+ *
+ * The reported information is used to attribute samples obtained from any
+ * Intel(R) VTune(TM) Amplifier collector. This API needs to be called
+ * after JIT compilation and before the first entry into the JIT-compiled
+ * code.
+ *
+ * @param[in] event_type - type of the data sent to the agent
+ * @param[in] EventSpecificData - pointer to event-specific data
+ *
+ * @returns 1 on success, otherwise 0.
+ */
+int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+/** @endcond */
+
+/** @} jitapi group */
+
+#endif /* __JITPROFILING_H__ */
diff --git a/ext/opcache/jit/zend_elf.c b/ext/opcache/jit/zend_elf.c
new file mode 100644
index 0000000000..f5180e0a96
--- /dev/null
+++ b/ext/opcache/jit/zend_elf.c
@@ -0,0 +1,109 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ | Xinchen Hui <laruence@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+#endif
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "zend_API.h"
+#include "zend_elf.h"
+
+static void* zend_elf_read_sect(int fd, zend_elf_sectheader *sect)
+{
+ void *s = emalloc(sect->size);
+
+ if (lseek(fd, sect->ofs, SEEK_SET) < 0) {
+ efree(s);
+ return NULL;
+ }
+ if (read(fd, s, sect->size) != (ssize_t)sect->size) {
+ efree(s);
+ return NULL;
+ }
+
+ return s;
+}
+
+void zend_elf_load_symbols(void)
+{
+ zend_elf_header hdr;
+ zend_elf_sectheader sect;
+ int i;
+#if defined(__linux__)
+ int fd = open("/proc/self/exe", O_RDONLY);
+#elif defined(__NetBSD__)
+ int fd = open("/proc/curproc/exe", O_RDONLY);
+#elif defined(__FreeBSD__)
+ char path[PATH_MAX];
+ size_t pathlen = sizeof(path);
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ if (sysctl(mib, 4, path, &pathlen, NULL, 0) == -1) {
+ return;
+ }
+ int fd = open(path, O_RDONLY);
+#else
+ // To complete eventually for other ELF platforms.
+ // Otherwise APPLE is Mach-O
+ int fd = -1;
+#endif
+
+ if (fd >= 0) {
+ if (read(fd, &hdr, sizeof(hdr)) == sizeof(hdr)
+ && hdr.emagic[0] == '\177'
+ && hdr.emagic[1] == 'E'
+ && hdr.emagic[2] == 'L'
+ && hdr.emagic[3] == 'F'
+ && lseek(fd, hdr.shofs, SEEK_SET) >= 0) {
+ for (i = 0; i < hdr.shnum; i++) {
+ if (read(fd, &sect, sizeof(sect)) == sizeof(sect)
+ && sect.type == ELFSECT_TYPE_SYMTAB) {
+ uint32_t n, count = sect.size / sizeof(zend_elf_symbol);
+ zend_elf_symbol *syms = zend_elf_read_sect(fd, &sect);
+ char *str_tbl;
+
+ if (syms) {
+ if (lseek(fd, hdr.shofs + sect.link * sizeof(sect), SEEK_SET) >= 0
+ && read(fd, &sect, sizeof(sect)) == sizeof(sect)
+ && (str_tbl = (char*)zend_elf_read_sect(fd, &sect)) != NULL) {
+ for (n = 0; n < count; n++) {
+ if (syms[n].name
+ && (ELFSYM_TYPE(syms[n].info) == ELFSYM_TYPE_FUNC
+ /*|| ELFSYM_TYPE(syms[n].info) == ELFSYM_TYPE_DATA*/)
+ && (ELFSYM_BIND(syms[n].info) == ELFSYM_BIND_LOCAL
+ /*|| ELFSYM_BIND(syms[n].info) == ELFSYM_BIND_GLOBAL*/)) {
+ zend_jit_disasm_add_symbol(str_tbl + syms[n].name, syms[n].value, syms[n].size);
+ }
+ }
+ efree(str_tbl);
+ }
+ efree(syms);
+ }
+ if (lseek(fd, hdr.shofs + (i + 1) * sizeof(sect), SEEK_SET) < 0) {
+ break;
+ }
+ }
+ }
+ }
+ close(fd);
+ }
+}
diff --git a/ext/opcache/jit/zend_elf.h b/ext/opcache/jit/zend_elf.h
new file mode 100644
index 0000000000..305e08708d
--- /dev/null
+++ b/ext/opcache/jit/zend_elf.h
@@ -0,0 +1,115 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ | Xinchen Hui <laruence@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_ELF
+#define ZEND_ELF
+
+#if SIZEOF_SIZE_T == 8
+# define ELF64
+#else
+# undef ELF64
+#endif
+
+typedef struct _zend_elf_header {
+ uint8_t emagic[4];
+ uint8_t eclass;
+ uint8_t eendian;
+ uint8_t eversion;
+ uint8_t eosabi;
+ uint8_t eabiversion;
+ uint8_t epad[7];
+ uint16_t type;
+ uint16_t machine;
+ uint32_t version;
+ uintptr_t entry;
+ uintptr_t phofs;
+ uintptr_t shofs;
+ uint32_t flags;
+ uint16_t ehsize;
+ uint16_t phentsize;
+ uint16_t phnum;
+ uint16_t shentsize;
+ uint16_t shnum;
+ uint16_t shstridx;
+} zend_elf_header;
+
+typedef struct zend_elf_sectheader {
+ uint32_t name;
+ uint32_t type;
+ uintptr_t flags;
+ uintptr_t addr;
+ uintptr_t ofs;
+ uintptr_t size;
+ uint32_t link;
+ uint32_t info;
+ uintptr_t align;
+ uintptr_t entsize;
+} zend_elf_sectheader;
+
+#define ELFSECT_IDX_ABS 0xfff1
+
+enum {
+ ELFSECT_TYPE_PROGBITS = 1,
+ ELFSECT_TYPE_SYMTAB = 2,
+ ELFSECT_TYPE_STRTAB = 3,
+ ELFSECT_TYPE_NOBITS = 8,
+ ELFSECT_TYPE_DYNSYM = 11,
+};
+
+#define ELFSECT_FLAGS_WRITE (1 << 0)
+#define ELFSECT_FLAGS_ALLOC (1 << 1)
+#define ELFSECT_FLAGS_EXEC (1 << 2)
+#define ELFSECT_FLAGS_TLS (1 << 10)
+
+typedef struct zend_elf_symbol {
+#ifdef ELF64
+ uint32_t name;
+ uint8_t info;
+ uint8_t other;
+ uint16_t sectidx;
+ uintptr_t value;
+ uint64_t size;
+#else
+ uint32_t name;
+ uintptr_t value;
+ uint32_t size;
+ uint8_t info;
+ uint8_t other;
+ uint16_t sectidx;
+#endif
+} zend_elf_symbol;
+
+#define ELFSYM_BIND(info) ((info) >> 4)
+#define ELFSYM_TYPE(info) ((info) & 0xf)
+#define ELFSYM_INFO(bind, type) (((bind) << 4) | (type))
+
+enum {
+ ELFSYM_TYPE_DATA = 2,
+ ELFSYM_TYPE_FUNC = 2,
+ ELFSYM_TYPE_FILE = 4,
+};
+
+enum {
+ ELFSYM_BIND_LOCAL = 0,
+ ELFSYM_BIND_GLOBAL = 1,
+};
+
+void zend_elf_load_symbols(void);
+
+#endif
diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c
new file mode 100644
index 0000000000..07d82b89de
--- /dev/null
+++ b/ext/opcache/jit/zend_jit.c
@@ -0,0 +1,3652 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <ZendAccelerator.h>
+#include "zend_shared_alloc.h"
+#include "Zend/zend_execute.h"
+#include "Zend/zend_vm.h"
+#include "Zend/zend_exceptions.h"
+#include "Zend/zend_constants.h"
+#include "zend_smart_str.h"
+#include "jit/zend_jit.h"
+#include "jit/zend_jit_internal.h"
+
+#ifdef HAVE_JIT
+
+#include "Optimizer/zend_func_info.h"
+#include "Optimizer/zend_ssa.h"
+#include "Optimizer/zend_inference.h"
+#include "Optimizer/zend_call_graph.h"
+#include "Optimizer/zend_dump.h"
+
+//#define CONTEXT_THREADED_JIT
+#define ZEND_JIT_USE_RC_INFERENCE
+
+#ifdef ZEND_JIT_USE_RC_INFERENCE
+# define ZEND_SSA_RC_INFERENCE_FLAG ZEND_SSA_RC_INFERENCE
+# define RC_MAY_BE_1(info) (((info) & (MAY_BE_RC1|MAY_BE_REF)) != 0)
+# define RC_MAY_BE_N(info) (((info) & (MAY_BE_RCN|MAY_BE_REF)) != 0)
+#else
+# define ZEND_SSA_RC_INFERENCE_FLAG 0
+# define RC_MAY_BE_1(info) 1
+# define RC_MAY_BE_N(info) 1
+#endif
+
+#define JIT_PREFIX "JIT$"
+#define JIT_STUB_PREFIX "JIT$$"
+
+#define DASM_M_GROW(ctx, t, p, sz, need) \
+ do { \
+ size_t _sz = (sz), _need = (need); \
+ if (_sz < _need) { \
+ if (_sz < 16) _sz = 16; \
+ while (_sz < _need) _sz += _sz; \
+ (p) = (t *)erealloc((p), _sz); \
+ (sz) = _sz; \
+ } \
+ } while(0)
+
+#define DASM_M_FREE(ctx, p, sz) efree(p)
+
+#include "dynasm/dasm_proto.h"
+
+typedef struct _zend_jit_stub {
+ const char *name;
+ int (*stub)(dasm_State **Dst);
+} zend_jit_stub;
+
+#define JIT_STUB(name) \
+ {JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub}
+
+static zend_uchar zend_jit_level = 0;
+static zend_uchar zend_jit_trigger = 0;
+static zend_uchar zend_jit_reg_alloc = 0;
+static zend_uchar zend_jit_cpu_flags = 0;
+
+zend_ulong zend_jit_profile_counter = 0;
+int zend_jit_profile_counter_rid = -1;
+
+int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT];
+
+const zend_op *zend_jit_halt_op = NULL;
+static int zend_jit_vm_kind = 0;
+
+static void *dasm_buf = NULL;
+static void *dasm_end = NULL;
+static void **dasm_ptr = NULL;
+
+static size_t dasm_size = 0;
+
+static zend_long jit_bisect_pos = 0;
+
+static const void *zend_jit_runtime_jit_handler = NULL;
+static const void *zend_jit_profile_jit_handler = NULL;
+static const void *zend_jit_func_counter_handler = NULL;
+static const void *zend_jit_loop_counter_handler = NULL;
+
+static int zend_may_overflow(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa);
+static void ZEND_FASTCALL zend_runtime_jit(void);
+
+static zend_bool zend_ssa_is_last_use(const zend_op_array *op_array, const zend_ssa *ssa, int var, int use)
+{
+ if (ssa->vars[var].phi_use_chain) {
+ zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
+ do {
+ if (!ssa->vars[phi->ssa_var].no_val) {
+ return 0;
+ }
+ phi = zend_ssa_next_use_phi(ssa, var, phi);
+ } while (phi);
+ }
+
+ use = zend_ssa_next_use(ssa->ops, var, use);
+ return use < 0 || zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var);
+}
+
+static zend_bool zend_is_commutative(zend_uchar opcode)
+{
+ return
+ opcode == ZEND_ADD ||
+ opcode == ZEND_MUL ||
+ opcode == ZEND_BW_OR ||
+ opcode == ZEND_BW_AND ||
+ opcode == ZEND_BW_XOR;
+}
+
+static zend_bool zend_long_is_power_of_two(zend_long x)
+{
+ return (x > 0) && !(x & (x - 1));
+}
+
+#define OP_RANGE(line, opN) \
+ (((opline->opN##_type & (IS_TMP_VAR|IS_VAR|IS_CV)) && \
+ ssa->ops && \
+ ssa->var_info && \
+ ssa->ops[line].opN##_use >= 0 && \
+ ssa->var_info[ssa->ops[line].opN##_use].has_range) ? \
+ &ssa->var_info[ssa->ops[line].opN##_use].range : NULL)
+
+#define OP1_RANGE() OP_RANGE(opline - op_array->opcodes, op1)
+#define OP2_RANGE() OP_RANGE(opline - op_array->opcodes, op2)
+#define OP1_DATA_RANGE() OP_RANGE(opline - op_array->opcodes + 1, op1)
+
+#include "dynasm/dasm_x86.h"
+#include "jit/zend_jit_x86.h"
+#include "jit/zend_jit_helpers.c"
+#include "jit/zend_jit_x86.c"
+#include "jit/zend_jit_disasm_x86.c"
+#ifndef _WIN32
+#include "jit/zend_jit_gdb.c"
+#include "jit/zend_jit_perf_dump.c"
+#endif
+#ifdef HAVE_OPROFILE
+# include "jit/zend_jit_oprofile.c"
+#endif
+#include "jit/zend_jit_vtune.c"
+
+#if _WIN32
+# include <Windows.h>
+#else
+# include <sys/mman.h>
+# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+# define MAP_ANONYMOUS MAP_ANON
+# endif
+#endif
+
+#define DASM_ALIGNMENT 16
+
+ZEND_EXT_API void zend_jit_status(zval *ret)
+{
+ zval stats;
+ array_init(&stats);
+ add_assoc_long(&stats, "level", zend_jit_level);
+ add_assoc_long(&stats, "trigger", zend_jit_trigger);
+ add_assoc_long(&stats, "reg-alloc", zend_jit_reg_alloc);
+ if (dasm_buf) {
+ add_assoc_long(&stats, "buffer_size", (char*)dasm_end - (char*)dasm_buf);
+ add_assoc_long(&stats, "buffer_free", (char*)dasm_end - (char*)*dasm_ptr);
+ } else {
+ add_assoc_long(&stats, "buffer_size", 0);
+ add_assoc_long(&stats, "buffer_free", 0);
+ }
+ add_assoc_zval(ret, "jit", &stats);
+}
+
+static zend_string *zend_jit_func_name(const zend_op_array *op_array)
+{
+ smart_str buf = {0};
+
+ if (op_array->function_name) {
+ if (op_array->scope) {
+ smart_str_appends(&buf, JIT_PREFIX);
+ smart_str_appendl(&buf, ZSTR_VAL(op_array->scope->name), ZSTR_LEN(op_array->scope->name));
+ smart_str_appends(&buf, "::");
+ smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
+ smart_str_0(&buf);
+ return buf.s;
+ } else {
+ smart_str_appends(&buf, JIT_PREFIX);
+ smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
+ smart_str_0(&buf);
+ return buf.s;
+ }
+ } else if (op_array->filename) {
+ smart_str_appends(&buf, JIT_PREFIX);
+ smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
+ smart_str_0(&buf);
+ return buf.s;
+ } else {
+ return NULL;
+ }
+}
+
+static void *dasm_link_and_encode(dasm_State **dasm_state,
+ const zend_op_array *op_array,
+ zend_ssa *ssa,
+ const zend_op *rt_opline,
+ zend_lifetime_interval **ra,
+ const char *name)
+{
+ size_t size;
+ int ret;
+ void *entry;
+#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE)
+ zend_string *str = NULL;
+#endif
+
+ if (rt_opline && ssa && ssa->cfg.map) {
+ /* Create additional entry point, to switch from interpreter to JIT-ed
+ * code at run-time.
+ */
+ int b = ssa->cfg.map[rt_opline - op_array->opcodes];
+
+//#ifdef CONTEXT_THREADED_JIT
+// if (!(ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY))) {
+//#else
+ if (!(ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY))) {
+//#endif
+ zend_jit_label(dasm_state, ssa->cfg.blocks_count + b);
+ zend_jit_prologue(dasm_state);
+ if (ra) {
+ int i;
+ zend_lifetime_interval *ival;
+ zend_life_range *range;
+ uint32_t pos = rt_opline - op_array->opcodes;
+
+ for (i = 0; i < ssa->vars_count; i++) {
+ ival = ra[i];
+
+ if (ival && ival->reg != ZREG_NONE) {
+ range = &ival->range;
+
+ if (pos >= range->start && pos <= range->end) {
+ if (!zend_jit_load_var(dasm_state, ssa->var_info[i].type, ssa->vars[i].var, ival->reg)) {
+ return NULL;
+ }
+ break;
+ }
+ range = range->next;
+ }
+ }
+ }
+ zend_jit_jmp(dasm_state, b);
+ }
+ }
+
+ if (dasm_link(dasm_state, &size) != DASM_S_OK) {
+ // TODO: dasm_link() failed ???
+ return NULL;
+ }
+
+ if ((void*)((char*)*dasm_ptr + size) > dasm_end) {
+ *dasm_ptr = dasm_end; //prevent further try
+ // TODO: jit_buffer_size overflow ???
+ return NULL;
+ }
+
+ ret = dasm_encode(dasm_state, *dasm_ptr);
+
+ if (ret != DASM_S_OK) {
+ // TODO: dasm_encode() failed ???
+ return NULL;
+ }
+
+ entry = *dasm_ptr;
+ *dasm_ptr = (void*)((char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(size, DASM_ALIGNMENT));
+
+ if (op_array && ssa) {
+ int b;
+
+ for (b = 0; b < ssa->cfg.blocks_count; b++) {
+//#ifdef CONTEXT_THREADED_JIT
+// if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) {
+//#else
+ if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
+//#endif
+ zend_op *opline = op_array->opcodes + ssa->cfg.blocks[b].start;
+ int offset = dasm_getpclabel(dasm_state, ssa->cfg.blocks_count + b);
+
+ if (offset >= 0) {
+ opline->handler = (void*)(((char*)entry) + offset);
+ }
+ }
+ }
+ if (rt_opline && ssa && ssa->cfg.map) {
+ int b = ssa->cfg.map[rt_opline - op_array->opcodes];
+ zend_op *opline = (zend_op*)rt_opline;
+ int offset = dasm_getpclabel(dasm_state, ssa->cfg.blocks_count + b);
+
+ if (offset >= 0) {
+ opline->handler = (void*)(((char*)entry) + offset);
+ }
+ }
+ }
+
+#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE)
+ if (!name) {
+ if (ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_OPROFILE|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_VTUNE|ZEND_JIT_DEBUG_PERF_DUMP)) {
+ str = zend_jit_func_name(op_array);
+ if (str) {
+ name = ZSTR_VAL(str);
+ }
+ }
+#ifdef HAVE_DISASM
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_ASM) {
+ zend_jit_disasm_add_symbol(name, (uintptr_t)entry, size);
+ zend_jit_disasm(
+ name,
+ (op_array && op_array->filename) ? ZSTR_VAL(op_array->filename) : NULL,
+ op_array,
+ &ssa->cfg,
+ entry,
+ size);
+ }
+ } else {
+ if (ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_ASM_STUBS|ZEND_JIT_DEBUG_ASM)) {
+ zend_jit_disasm_add_symbol(name, (uintptr_t)entry, size);
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_ASM_STUBS) {
+ zend_jit_disasm(
+ name,
+ (op_array && op_array->filename) ? ZSTR_VAL(op_array->filename) : NULL,
+ op_array,
+ &ssa->cfg,
+ entry,
+ size);
+ }
+ }
+# endif
+ }
+#endif
+
+#ifdef HAVE_GDB
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_GDB) {
+ if (name) {
+ zend_jit_gdb_register(
+ name,
+ op_array,
+ entry,
+ size);
+ }
+ }
+#endif
+
+#ifdef HAVE_OPROFILE
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_OPROFILE) {
+ zend_jit_oprofile_register(
+ name,
+ entry,
+ size);
+ }
+#endif
+
+#ifdef HAVE_PERFTOOLS
+ if (ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
+ if (name) {
+ zend_jit_perf_map_register(
+ name,
+ entry,
+ size);
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_PERF_DUMP) {
+ zend_jit_perf_jitdump_register(
+ name,
+ entry,
+ size);
+ }
+ }
+ }
+#endif
+
+#ifdef HAVE_VTUNE
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_VTUNE) {
+ if (name) {
+ zend_jit_vtune_register(
+ name,
+ entry,
+ size);
+ }
+ }
+#endif
+
+#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_OPROFILE) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE)
+ if (str) {
+ zend_string_release(str);
+ }
+#endif
+
+ return entry;
+}
+
+static int zend_may_overflow(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa)
+{
+ uint32_t num;
+ int res;
+
+ if (!ssa->ops || !ssa->var_info) {
+ return 1;
+ }
+ switch (opline->opcode) {
+ case ZEND_PRE_INC:
+ case ZEND_POST_INC:
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].op1_def;
+ return (res < 0 ||
+ !ssa->var_info[res].has_range ||
+ ssa->var_info[res].range.overflow);
+ case ZEND_PRE_DEC:
+ case ZEND_POST_DEC:
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].op1_def;
+ return (res < 0 ||
+ !ssa->var_info[res].has_range ||
+ ssa->var_info[res].range.underflow);
+ case ZEND_ADD:
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].result_def;
+ if (res < 0 ||
+ !ssa->var_info[res].has_range) {
+ return 1;
+ }
+ if (ssa->var_info[res].range.underflow) {
+ zend_long op1_min, op2_min;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ if (zend_add_will_overflow(op1_min, op2_min)) {
+ return 1;
+ }
+ }
+ if (ssa->var_info[res].range.overflow) {
+ zend_long op1_max, op2_max;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ if (zend_add_will_overflow(op1_max, op2_max)) {
+ return 1;
+ }
+ }
+ return 0;
+ case ZEND_SUB:
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].result_def;
+ if (res < 0 ||
+ !ssa->var_info[res].has_range) {
+ return 1;
+ }
+ if (ssa->var_info[res].range.underflow) {
+ zend_long op1_min, op2_max;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_min = OP1_MIN_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ if (zend_sub_will_overflow(op1_min, op2_max)) {
+ return 1;
+ }
+ }
+ if (ssa->var_info[res].range.overflow) {
+ zend_long op1_max, op2_min;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_max = OP1_MAX_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ if (zend_sub_will_overflow(op1_max, op2_min)) {
+ return 1;
+ }
+ }
+ return 0;
+ case ZEND_MUL:
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].result_def;
+ return (res < 0 ||
+ !ssa->var_info[res].has_range ||
+ ssa->var_info[res].range.underflow ||
+ ssa->var_info[res].range.overflow);
+ case ZEND_ASSIGN_OP:
+ if (opline->extended_value == ZEND_ADD) {
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].op1_def;
+ if (res < 0 ||
+ !ssa->var_info[res].has_range) {
+ return 1;
+ }
+ if (ssa->var_info[res].range.underflow) {
+ zend_long op1_min, op2_min;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_min = OP1_MIN_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ if (zend_add_will_overflow(op1_min, op2_min)) {
+ return 1;
+ }
+ }
+ if (ssa->var_info[res].range.overflow) {
+ zend_long op1_max, op2_max;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_max = OP1_MAX_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ if (zend_add_will_overflow(op1_max, op2_max)) {
+ return 1;
+ }
+ }
+ return 0;
+ } else if (opline->extended_value == ZEND_SUB) {
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].op1_def;
+ if (res < 0 ||
+ !ssa->var_info[res].has_range) {
+ return 1;
+ }
+ if (ssa->var_info[res].range.underflow) {
+ zend_long op1_min, op2_max;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_min = OP1_MIN_RANGE();
+ op2_max = OP2_MAX_RANGE();
+ if (zend_sub_will_overflow(op1_min, op2_max)) {
+ return 1;
+ }
+ }
+ if (ssa->var_info[res].range.overflow) {
+ zend_long op1_max, op2_min;
+
+ if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
+ return 1;
+ }
+ op1_max = OP1_MAX_RANGE();
+ op2_min = OP2_MIN_RANGE();
+ if (zend_sub_will_overflow(op1_max, op2_min)) {
+ return 1;
+ }
+ }
+ return 0;
+ } else if (opline->extended_value == ZEND_MUL) {
+ num = opline - op_array->opcodes;
+ res = ssa->ops[num].op1_def;
+ return (res < 0 ||
+ !ssa->var_info[res].has_range ||
+ ssa->var_info[res].range.underflow ||
+ ssa->var_info[res].range.overflow);
+ }
+ default:
+ return 1;
+ }
+}
+
+static int zend_jit_build_cfg(const zend_op_array *op_array, zend_cfg *cfg)
+{
+ uint32_t flags;
+
+ flags = ZEND_CFG_STACKLESS | ZEND_CFG_NO_ENTRY_PREDECESSORS | ZEND_SSA_RC_INFERENCE_FLAG | ZEND_SSA_USE_CV_RESULTS | ZEND_CFG_RECV_ENTRY;
+
+ if (zend_build_cfg(&CG(arena), op_array, flags, cfg) != SUCCESS) {
+ return FAILURE;
+ }
+
+ /* Don't JIT huge functions. Apart from likely being detrimental due to the amount of
+ * generated code, some of our analysis is recursive and will stack overflow with many
+ * blocks. */
+ if (cfg->blocks_count > 100000) {
+ return FAILURE;
+ }
+
+ if (zend_cfg_build_predecessors(&CG(arena), cfg) != SUCCESS) {
+ return FAILURE;
+ }
+
+ /* Compute Dominators Tree */
+ if (zend_cfg_compute_dominators_tree(op_array, cfg) != SUCCESS) {
+ return FAILURE;
+ }
+
+ /* Identify reducible and irreducible loops */
+ if (zend_cfg_identify_loops(op_array, cfg) != SUCCESS) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+static int zend_jit_op_array_analyze1(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa)
+{
+ if (zend_jit_build_cfg(op_array, &ssa->cfg) != SUCCESS) {
+ return FAILURE;
+ }
+
+#if 0
+ /* TODO: debugger and profiler supports? */
+ if ((ssa->cfg.flags & ZEND_FUNC_HAS_EXTENDED_INFO)) {
+ return FAILURE;
+ }
+#endif
+
+ if ((zend_jit_level >= ZEND_JIT_LEVEL_OPT_FUNC)
+ && ssa->cfg.blocks
+ && op_array->last_try_catch == 0
+ && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
+ && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
+ if (zend_build_ssa(&CG(arena), script, op_array, ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS, ssa) != SUCCESS) {
+ return FAILURE;
+ }
+
+ if (zend_ssa_compute_use_def_chains(&CG(arena), op_array, ssa) != SUCCESS) {
+ return FAILURE;
+ }
+
+ if (zend_ssa_find_false_dependencies(op_array, ssa) != SUCCESS) {
+ return FAILURE;
+ }
+
+ if (zend_ssa_find_sccs(op_array, ssa) != SUCCESS){
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+
+static int zend_jit_op_array_analyze2(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa)
+{
+ if ((zend_jit_level >= ZEND_JIT_LEVEL_OPT_FUNC)
+ && ssa->cfg.blocks
+ && op_array->last_try_catch == 0
+ && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
+ && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) {
+
+ uint32_t optimization_level = ZCG(accel_directives).optimization_level;
+ if (zend_ssa_inference(&CG(arena), op_array, script, ssa, optimization_level) != SUCCESS) {
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+
+static int zend_jit_add_range(zend_lifetime_interval **intervals, int var, uint32_t from, uint32_t to)
+{
+ zend_lifetime_interval *ival = intervals[var];
+
+ if (!ival) {
+ ival = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval));
+ if (!ival) {
+ return FAILURE;
+ }
+ ival->ssa_var = var;
+ ival->reg = ZREG_NONE;
+ ival->split = 0;
+ ival->store = 0;
+ ival->load = 0;
+ ival->range.start = from;
+ ival->range.end = to;
+ ival->range.next = NULL;
+ ival->hint = NULL;
+ ival->used_as_hint = NULL;
+ intervals[var] = ival;
+ } else if (ival->range.start > to + 1) {
+ zend_life_range *range = zend_arena_alloc(&CG(arena), sizeof(zend_life_range));
+
+ if (!range) {
+ return FAILURE;
+ }
+ range->start = ival->range.start;
+ range->end = ival->range.end;
+ range->next = ival->range.next;
+ ival->range.start = from;
+ ival->range.end = to;
+ ival->range.next = range;
+ } else if (ival->range.start == to + 1) {
+ ival->range.start = from;
+ } else {
+ zend_life_range *range = &ival->range;
+ zend_life_range *last = NULL;
+
+ do {
+ if (range->start > to + 1) {
+ break;
+ } else if (range->end + 1 >= from) {
+ if (range->start > from) {
+ range->start = from;
+ }
+ last = range;
+ range = range->next;
+ while (range) {
+ if (range->start > to + 1) {
+ break;
+ }
+ last->end = range->end;
+ range = range->next;
+ last->next = range;
+ }
+ if (to > last->end) {
+ last->end = to;
+ }
+ return SUCCESS;
+ }
+ last = range;
+ range = range->next;
+ } while (range);
+
+ range = zend_arena_alloc(&CG(arena), sizeof(zend_life_range));
+ if (!range) {
+ return FAILURE;
+ }
+ range->start = from;
+ range->end = to;
+ range->next = last->next;
+ last->next = range;
+ }
+
+ return SUCCESS;
+}
+
+static int zend_jit_begin_range(zend_lifetime_interval **intervals, int var, uint32_t block_start, uint32_t from)
+{
+ if (block_start != from && intervals[var]) {
+ zend_life_range *range = &intervals[var]->range;
+
+ do {
+ if (from >= range->start && from <= range->end) {
+ if (range->start == block_start) {
+ range->start = from;
+ } else {
+ zend_life_range *r = zend_arena_alloc(&CG(arena), sizeof(zend_life_range));
+ if (!r) {
+ return FAILURE;
+ }
+ r->start = from;
+ r->end = range->end;
+ r->next = range->next;
+ range->end = block_start - 1;
+ range->next = r;
+ }
+ return SUCCESS;
+ }
+ range = range->next;
+ } while (range);
+ }
+
+ // dead store
+ return zend_jit_add_range(intervals, var, from, from);
+}
+
+static void zend_jit_insert_interval(zend_lifetime_interval **list, zend_lifetime_interval *ival)
+{
+ while (1) {
+ if (*list == NULL) {
+ *list = ival;
+ ival->list_next = NULL;
+ return;
+ } else if (ival->range.start < (*list)->range.start) {
+ ival->list_next = *list;
+ *list = ival;
+ return;
+ }
+ list = &(*list)->list_next;
+ }
+}
+
+static int zend_jit_split_interval(zend_lifetime_interval *current, uint32_t pos, zend_lifetime_interval **list, zend_lifetime_interval **free)
+{
+ zend_lifetime_interval *ival;
+ zend_life_range *range = &current->range;
+ zend_life_range *prev = NULL;
+
+ if (*free) {
+ ival = *free;
+ *free = ival->list_next;
+ } else {
+ ival = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval));
+
+ if (!ival) {
+ return FAILURE;
+ }
+ }
+
+ current->store = 1;
+
+ ival->ssa_var = current->ssa_var;
+ ival->reg = ZREG_NONE;
+ ival->split = 1;
+ ival->store = 0;
+ ival->load = 1;
+ ival->hint = NULL;
+
+ do {
+ if (pos >= range->start && pos <= range->end) {
+ break;
+ }
+ prev = range;
+ range = range->next;
+ } while(range);
+
+ ZEND_ASSERT(range != NULL);
+
+ ival->range.start = pos;
+ ival->range.end = range->end;
+ ival->range.next = range->next;
+
+ if (pos == range->start) {
+ ZEND_ASSERT(prev != NULL);
+ prev->next = NULL;
+ } else {
+ range->end = pos - 1;
+ }
+
+ zend_jit_insert_interval(list, ival);
+
+ return SUCCESS;
+}
+
+static zend_lifetime_interval *zend_jit_sort_intervals(zend_lifetime_interval **intervals, int count)
+{
+ zend_lifetime_interval *list, *last;
+ int i;
+
+ list = NULL;
+ i = 0;
+ while (i < count) {
+ list = intervals[i];
+ i++;
+ if (list) {
+ last = list;
+ last->list_next = NULL;
+ break;
+ }
+ }
+
+ while (i < count) {
+ zend_lifetime_interval *ival = intervals[i];
+
+ i++;
+ if (ival) {
+ if ((ival->range.start > last->range.start) ||
+ (ival->range.start == last->range.start &&
+ ival->range.end > last->range.end)) {
+ last->list_next = ival;
+ last = ival;
+ ival->list_next = NULL;
+ } else {
+ zend_lifetime_interval **p = &list;
+
+ while (1) {
+ if (*p == NULL) {
+ *p = last = ival;
+ ival->list_next = NULL;
+ break;
+ } else if ((ival->range.start < (*p)->range.start) ||
+ (ival->range.start == (*p)->range.start &&
+ ival->range.end < (*p)->range.end)) {
+ ival->list_next = *p;
+ *p = ival;
+ break;
+ }
+ p = &(*p)->list_next;
+ }
+ }
+ }
+ }
+
+ return list;
+}
+
+static ZEND_ATTRIBUTE_UNUSED void zend_jit_print_regset(zend_regset regset)
+{
+ zend_reg reg;
+ int first = 1;
+
+ ZEND_REGSET_FOREACH(regset, reg) {
+ if (first) {
+ first = 0;
+ fprintf(stderr, "%s", zend_reg_name[reg]);
+ } else {
+ fprintf(stderr, ", %s", zend_reg_name[reg]);
+ }
+ } ZEND_REGSET_FOREACH_END();
+}
+
+static int *zend_jit_compute_block_order_int(zend_ssa *ssa, int n, int *block_order)
+{
+ zend_basic_block *b = ssa->cfg.blocks + n;
+
+tail_call:
+ *block_order = n;
+ block_order++;
+
+ n = b->children;
+ while (n >= 0) {
+ b = ssa->cfg.blocks + n;
+ if (b->next_child < 0) {
+ goto tail_call;
+ }
+ block_order = zend_jit_compute_block_order_int(ssa, n, block_order);
+ n = b->next_child;
+ }
+
+ return block_order;
+}
+
+static int zend_jit_compute_block_order(zend_ssa *ssa, int *block_order)
+{
+ int *end = zend_jit_compute_block_order_int(ssa, 0, block_order);
+
+ return end - block_order;
+}
+
+static zend_bool zend_jit_in_loop(zend_ssa *ssa, int header, zend_basic_block *b)
+{
+ while (b->loop_header >= 0) {
+ if (b->loop_header == header) {
+ return 1;
+ }
+ b = ssa->cfg.blocks + b->loop_header;
+ }
+ return 0;
+}
+
+static void zend_jit_compute_loop_body(zend_ssa *ssa, int header, int n, zend_bitset loop_body)
+{
+ zend_basic_block *b = ssa->cfg.blocks + n;
+ uint32_t i;
+
+tail_call:
+ if (b->len) {
+ for (i = b->start; i < b->start + b->len; i++) {
+ zend_bitset_incl(loop_body, i);
+ }
+ }
+
+ n = b->children;
+ while (n >= 0) {
+ b = ssa->cfg.blocks + n;
+ if (zend_jit_in_loop(ssa, header, b)) {
+ if (b->next_child < 0) {
+ goto tail_call;
+ }
+ zend_jit_compute_loop_body(ssa, header, n, loop_body);
+ }
+ n = b->next_child;
+ }
+}
+
+static void zend_jit_add_hint(zend_lifetime_interval **intervals, int dst, int src)
+{
+ if (intervals[dst]->range.start < intervals[src]->range.start) {
+ int tmp = src;
+ src = dst;
+ dst = tmp;
+ }
+ while (1) {
+ if (intervals[dst]->hint) {
+ if (intervals[dst]->hint->range.start < intervals[src]->range.start) {
+ int tmp = src;
+ src = intervals[dst]->hint->ssa_var;
+ dst = tmp;
+ } else {
+ dst = intervals[dst]->hint->ssa_var;
+ }
+ } else {
+ if (dst != src) {
+ intervals[dst]->hint = intervals[src];
+ }
+ return;
+ }
+ }
+}
+
+/* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
+ Michael Franz, CGO'10 (2010), Figure 4. */
+static int zend_jit_compute_liveness(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset candidates, zend_lifetime_interval **list)
+{
+ int set_size, i, j, k, l;
+ uint32_t n;
+ zend_bitset live, live_in, pi_vars, loop_body;
+ int *block_order;
+ zend_ssa_phi *phi;
+ zend_lifetime_interval **intervals;
+ size_t mem_size;
+ ALLOCA_FLAG(use_heap);
+
+ set_size = zend_bitset_len(ssa->vars_count);
+ mem_size =
+ ZEND_MM_ALIGNED_SIZE(ssa->vars_count * sizeof(zend_lifetime_interval*)) +
+ ZEND_MM_ALIGNED_SIZE((set_size * ssa->cfg.blocks_count) * ZEND_BITSET_ELM_SIZE) +
+ ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE) +
+ ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE) +
+ ZEND_MM_ALIGNED_SIZE(zend_bitset_len(op_array->last) * ZEND_BITSET_ELM_SIZE) +
+ ZEND_MM_ALIGNED_SIZE(ssa->cfg.blocks_count * sizeof(int));
+ intervals = do_alloca(mem_size, use_heap);
+ if (!intervals) {
+ *list = NULL;
+ return FAILURE;
+ }
+
+ live_in = (zend_bitset)((char*)intervals + ZEND_MM_ALIGNED_SIZE(ssa->vars_count * sizeof(zend_lifetime_interval*)));
+ live = (zend_bitset)((char*)live_in + ZEND_MM_ALIGNED_SIZE((set_size * ssa->cfg.blocks_count) * ZEND_BITSET_ELM_SIZE));
+ pi_vars = (zend_bitset)((char*)live + ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE));
+ loop_body = (zend_bitset)((char*)pi_vars + ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE));
+ block_order = (int*)((char*)loop_body + ZEND_MM_ALIGNED_SIZE(zend_bitset_len(op_array->last) * ZEND_BITSET_ELM_SIZE));
+
+ memset(intervals, 0, ssa->vars_count * sizeof(zend_lifetime_interval*));
+ zend_bitset_clear(live_in, set_size * ssa->cfg.blocks_count);
+
+ /* TODO: Provide a linear block order where all dominators of a block
+ * are before this block, and where all blocks belonging to the same loop
+ * are contiguous ???
+ */
+ for (l = zend_jit_compute_block_order(ssa, block_order) - 1; l >= 0; l--) {
+ zend_basic_block *b;
+
+ i = block_order[l];
+ b = ssa->cfg.blocks + i;
+
+ /* live = UNION of successor.liveIn for each successor of b */
+ /* live.add(phi.inputOf(b)) for each phi of successors of b */
+ zend_bitset_clear(live, set_size);
+ for (j = 0; j < b->successors_count; j++) {
+ int succ = b->successors[j];
+
+ zend_bitset_union(live, live_in + set_size * succ, set_size);
+ zend_bitset_clear(pi_vars, set_size);
+ for (phi = ssa->blocks[succ].phis; phi; phi = phi->next) {
+ if (ssa->vars[phi->ssa_var].no_val) {
+ /* skip */
+ } else if (phi->pi >= 0) {
+ if (phi->pi == i && phi->sources[0] >= 0) {
+ if (zend_bitset_in(candidates, phi->sources[0])) {
+ zend_bitset_incl(live, phi->sources[0]);
+ }
+ zend_bitset_incl(pi_vars, phi->var);
+ }
+ } else if (!zend_bitset_in(pi_vars, phi->var)) {
+ for (k = 0; k < ssa->cfg.blocks[succ].predecessors_count; k++) {
+ if (ssa->cfg.predecessors[ssa->cfg.blocks[succ].predecessor_offset + k] == i) {
+ if (phi->sources[k] >= 0 && zend_bitset_in(candidates, phi->sources[k])) {
+ zend_bitset_incl(live, phi->sources[k]);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* addRange(var, b.from, b.to) for each var in live */
+ ZEND_BITSET_FOREACH(live, set_size, j) {
+ if (zend_bitset_in(candidates, j)) {
+ if (zend_jit_add_range(intervals, j, b->start, b->start + b->len - 1) != SUCCESS) {
+ goto failure;
+ }
+ }
+ } ZEND_BITSET_FOREACH_END();
+
+ /* for each operation op of b in reverse order */
+ for (n = b->start + b->len; n > b->start;) {
+ zend_ssa_op *op;
+ const zend_op *opline;
+ uint32_t num;
+
+ n--;
+ op = ssa->ops + n;
+ opline = op_array->opcodes + n;
+
+ if (UNEXPECTED(opline->opcode == ZEND_OP_DATA)) {
+ num = n - 1;
+ } else {
+ num = n;
+ }
+
+ /* for each output operand opd of op do */
+ /* setFrom(opd, op) */
+ /* live.remove(opd) */
+ if (op->op1_def >= 0 && zend_bitset_in(candidates, op->op1_def)) {
+ if (zend_jit_begin_range(intervals, op->op1_def, b->start, num) != SUCCESS) {
+ goto failure;
+ }
+ zend_bitset_excl(live, op->op1_def);
+ }
+ if (op->op2_def >= 0 && zend_bitset_in(candidates, op->op2_def)) {
+ if (zend_jit_begin_range(intervals, op->op2_def, b->start, num) != SUCCESS) {
+ goto failure;
+ }
+ zend_bitset_excl(live, op->op2_def);
+ }
+ if (op->result_def >= 0 && zend_bitset_in(candidates, op->result_def)) {
+ if (zend_jit_begin_range(intervals, op->result_def, b->start, num) != SUCCESS) {
+ goto failure;
+ }
+ zend_bitset_excl(live, op->result_def);
+ }
+
+ /* for each input operand opd of op do */
+ /* live.add(opd) */
+ /* addRange(opd, b.from, op) */
+ if (op->op1_use >= 0
+ && zend_bitset_in(candidates, op->op1_use)
+ && !zend_ssa_is_no_val_use(opline, op, op->op1_use)) {
+ zend_bitset_incl(live, op->op1_use);
+ if (zend_jit_add_range(intervals, op->op1_use, b->start, num) != SUCCESS) {
+ goto failure;
+ }
+ }
+ if (op->op2_use >= 0
+ && zend_bitset_in(candidates, op->op2_use)
+ && !zend_ssa_is_no_val_use(opline, op, op->op2_use)) {
+ zend_bitset_incl(live, op->op2_use);
+ if (zend_jit_add_range(intervals, op->op2_use, b->start, num) != SUCCESS) {
+ goto failure;
+ }
+ }
+ if (op->result_use >= 0
+ && zend_bitset_in(candidates, op->result_use)
+ && !zend_ssa_is_no_val_use(opline, op, op->result_use)) {
+ zend_bitset_incl(live, op->result_use);
+ if (zend_jit_add_range(intervals, op->result_use, b->start, num) != SUCCESS) {
+ goto failure;
+ }
+ }
+ }
+
+ /* live.remove(phi.output) for each phi of b */
+ for (phi = ssa->blocks[i].phis; phi; phi = phi->next) {
+ zend_bitset_excl(live, phi->ssa_var);
+ }
+
+ /* b.liveIn = live */
+ zend_bitset_copy(live_in + set_size * i, live, set_size);
+ }
+
+ for (i = ssa->cfg.blocks_count - 1; i >= 0; i--) {
+ zend_basic_block *b = ssa->cfg.blocks + i;
+
+ /* if b is loop header */
+ if ((b->flags & ZEND_BB_LOOP_HEADER)) {
+ live = live_in + set_size * i;
+
+ if (!zend_bitset_empty(live, set_size)) {
+ uint32_t set_size2 = zend_bitset_len(op_array->last);
+
+ zend_bitset_clear(loop_body, set_size2);
+ zend_jit_compute_loop_body(ssa, i, i, loop_body);
+ while (!zend_bitset_empty(loop_body, set_size2)) {
+ uint32_t from = zend_bitset_first(loop_body, set_size2);
+ uint32_t to = from;
+
+ do {
+ zend_bitset_excl(loop_body, to);
+ to++;
+ } while (zend_bitset_in(loop_body, to));
+ to--;
+
+ ZEND_BITSET_FOREACH(live, set_size, j) {
+ if (zend_jit_add_range(intervals, j, from, to) != SUCCESS) {
+ goto failure;
+ }
+ } ZEND_BITSET_FOREACH_END();
+ }
+ }
+ }
+
+ }
+
+ if (zend_jit_reg_alloc >= ZEND_JIT_REG_ALLOC_GLOBAL) {
+ /* Register hinting (a cheap way for register coalescing) */
+ for (i = 0; i < ssa->vars_count; i++) {
+ if (intervals[i]) {
+ int var = intervals[i]->ssa_var;
+ int src;
+
+ if (ssa->vars[var].definition_phi) {
+ zend_ssa_phi *phi = ssa->vars[var].definition_phi;
+
+ if (phi->pi >= 0) {
+ src = phi->sources[0];
+ if (intervals[src]) {
+ zend_jit_add_hint(intervals, i, src);
+ }
+ } else {
+ for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
+ src = phi->sources[k];
+ if (src >= 0) {
+ if (ssa->vars[src].definition_phi
+ && ssa->vars[src].definition_phi->pi >= 0
+ && phi->block == ssa->vars[src].definition_phi->block) {
+ /* Skip zero-lenght interval for Pi variable */
+ src = ssa->vars[src].definition_phi->sources[0];
+ }
+ if (intervals[src]) {
+ zend_jit_add_hint(intervals, i, src);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ for (i = 0; i < ssa->vars_count; i++) {
+ if (intervals[i] && !intervals[i]->hint) {
+ int var = intervals[i]->ssa_var;
+
+ if (ssa->vars[var].definition >= 0) {
+ uint32_t line = ssa->vars[var].definition;
+ const zend_op *opline = op_array->opcodes + line;
+
+ switch (opline->opcode) {
+ case ZEND_QM_ASSIGN:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ if (ssa->ops[line].op1_use >= 0 &&
+ intervals[ssa->ops[line].op1_use] &&
+ (var == ssa->ops[line].op1_def ||
+ (var == ssa->ops[line].result_def &&
+ (ssa->ops[line].op1_def < 0 ||
+ !intervals[ssa->ops[line].op1_def])))) {
+ zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
+ }
+ break;
+ case ZEND_SEND_VAR:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ if (var == ssa->ops[line].op1_def &&
+ ssa->ops[line].op1_use >= 0 &&
+ intervals[ssa->ops[line].op1_use]) {
+ zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use);
+ }
+ break;
+ case ZEND_ASSIGN:
+ if (ssa->ops[line].op2_use >= 0 &&
+ intervals[ssa->ops[line].op2_use] &&
+ (var == ssa->ops[line].op2_def ||
+ (var == ssa->ops[line].op1_def &&
+ (ssa->ops[line].op2_def < 0 ||
+ !intervals[ssa->ops[line].op2_def])) ||
+ (var == ssa->ops[line].result_def &&
+ (ssa->ops[line].op2_def < 0 ||
+ !intervals[ssa->ops[line].op2_def]) &&
+ (ssa->ops[line].op1_def < 0 ||
+ !intervals[ssa->ops[line].op1_def])))) {
+ zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ *list = zend_jit_sort_intervals(intervals, ssa->vars_count);
+
+ if (*list) {
+ zend_lifetime_interval *ival = *list;
+ while (ival) {
+ if (ival->hint) {
+ ival->hint->used_as_hint = ival;
+ }
+ ival = ival->list_next;
+ }
+ }
+
+ free_alloca(intervals, use_heap);
+ return SUCCESS;
+
+failure:
+ *list = NULL;
+ free_alloca(intervals, use_heap);
+ return FAILURE;
+}
+
+static uint32_t zend_interval_end(zend_lifetime_interval *ival)
+{
+ zend_life_range *range = &ival->range;
+
+ while (range->next) {
+ range = range->next;
+ }
+ return range->end;
+}
+
+static zend_bool zend_interval_covers(zend_lifetime_interval *ival, uint32_t position)
+{
+ zend_life_range *range = &ival->range;
+
+ do {
+ if (position >= range->start && position <= range->end) {
+ return 1;
+ }
+ range = range->next;
+ } while (range);
+
+ return 0;
+}
+
+static uint32_t zend_interval_intersection(zend_lifetime_interval *ival1, zend_lifetime_interval *ival2)
+{
+ zend_life_range *r1 = &ival1->range;
+ zend_life_range *r2 = &ival2->range;
+
+ do {
+ if (r1->start <= r2->end) {
+ if (r2->start <= r1->end) {
+ return MAX(r1->start, r2->start);
+ } else {
+ r2 = r2->next;
+ }
+ } else {
+ r1 = r1->next;
+ }
+ } while (r1 && r2);
+
+ return 0xffffffff;
+}
+
+/* See "Optimized Interval Splitting in a Linear Scan Register Allocator",
+ Christian Wimmer VEE'05 (2005), Figure 4. Allocation without spilling */
+static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, zend_ssa *ssa, zend_lifetime_interval *current, zend_regset available, zend_regset *hints, zend_lifetime_interval *active, zend_lifetime_interval *inactive, zend_lifetime_interval **list, zend_lifetime_interval **free)
+{
+ zend_lifetime_interval *it;
+ uint32_t freeUntilPos[ZREG_NUM];
+ uint32_t pos, pos2;
+ zend_reg i, reg, reg2;
+ zend_reg hint = ZREG_NONE;
+ zend_regset low_priority_regs;
+ zend_life_range *range;
+
+ if ((ssa->var_info[current->ssa_var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+ available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_FP);
+ } else {
+ available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_GP);
+ }
+
+ /* TODO: Allow usage of preserved registers ???
+ * Their values have to be stored in prologuee and restored in epilogue
+ */
+ available = ZEND_REGSET_DIFFERENCE(available, ZEND_REGSET_PRESERVED);
+
+ if (ZEND_REGSET_IS_EMPTY(available)) {
+ return 0;
+ }
+
+ /* Set freeUntilPos of all physical registers to maxInt */
+ for (i = 0; i < ZREG_NUM; i++) {
+ freeUntilPos[i] = 0xffffffff;
+ }
+
+ /* for each interval it in active do */
+ /* freeUntilPos[it.reg] = 0 */
+ it = active;
+ if (ssa->vars[current->ssa_var].definition == current->range.start) {
+ while (it) {
+ if (current->range.start != zend_interval_end(it)) {
+ freeUntilPos[it->reg] = 0;
+ } else if (zend_jit_may_reuse_reg(op_array, ssa, current->range.start, current->ssa_var, it->ssa_var)) {
+ if (!ZEND_REGSET_IN(*hints, it->reg) &&
+ /* TODO: Avoid most often scratch registers. Find a better way ??? */
+ (!current->used_as_hint ||
+ (it->reg != ZREG_R0 && it->reg != ZREG_R1 && it->reg != ZREG_XMM0 && it->reg != ZREG_XMM1))) {
+ hint = it->reg;
+ }
+ } else {
+ freeUntilPos[it->reg] = 0;
+ }
+ it = it->list_next;
+ }
+ } else {
+ while (it) {
+ freeUntilPos[it->reg] = 0;
+ it = it->list_next;
+ }
+ }
+ if (current->hint) {
+ hint = current->hint->reg;
+ if (hint != ZREG_NONE && current->hint->used_as_hint == current) {
+ ZEND_REGSET_EXCL(*hints, hint);
+ }
+ }
+
+ /* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
+ Michael Franz, CGO'10 (2010), Figure 6. */
+ if (current->split) {
+ /* for each interval it in inactive intersecting with current do */
+ /* freeUntilPos[it.reg] = next intersection of it with current */
+ it = inactive;
+ while (it) {
+ uint32_t next = zend_interval_intersection(current, it);
+
+ //ZEND_ASSERT(next != 0xffffffff && !current->split);
+ if (next < freeUntilPos[it->reg]) {
+ freeUntilPos[it->reg] = next;
+ }
+ it = it->list_next;
+ }
+ }
+
+ /* Handle Scratch Registers */
+ /* TODO: Optimize ??? */
+ range = &current->range;
+ do {
+ uint32_t line = range->start;
+ zend_regset regset;
+ zend_reg reg;
+
+ if (ssa->ops[line].op1_def == current->ssa_var ||
+ ssa->ops[line].op2_def == current->ssa_var ||
+ ssa->ops[line].result_def == current->ssa_var) {
+ line++;
+ }
+ while (line <= range->end) {
+ regset = zend_jit_get_scratch_regset(op_array, ssa, line, current->ssa_var);
+ ZEND_REGSET_FOREACH(regset, reg) {
+ if (line < freeUntilPos[reg]) {
+ freeUntilPos[reg] = line;
+ }
+ } ZEND_REGSET_FOREACH_END();
+ line++;
+ }
+ range = range->next;
+ } while (range);
+
+#if 0
+ /* Coalesing */
+ if (ssa->vars[current->ssa_var].definition == current->start) {
+ zend_op *opline = op_array->opcodes + current->start;
+ int hint = -1;
+
+ switch (opline->opcode) {
+ case ZEND_ASSIGN:
+ hint = ssa->ops[current->start].op2_use;
+ case ZEND_QM_ASSIGN:
+ hint = ssa->ops[current->start].op1_use;
+ break;
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ hint = ssa->ops[current->start].op1_use;
+ break;
+ case ZEND_ASSIGN_OP:
+ if (opline->extended_value == ZEND_ADD
+ || opline->extended_value == ZEND_SUB
+ || opline->extended_value == ZEND_MUL) {
+ hint = ssa->ops[current->start].op1_use;
+ }
+ break;
+ }
+ if (hint >= 0) {
+ }
+ }
+#endif
+
+ if (hint != ZREG_NONE && freeUntilPos[hint] > zend_interval_end(current)) {
+ current->reg = hint;
+ if (current->used_as_hint) {
+ ZEND_REGSET_INCL(*hints, hint);
+ }
+ return 1;
+ }
+
+ pos = 0; reg = ZREG_NONE;
+ pos2 = 0; reg2 = ZREG_NONE;
+ low_priority_regs = *hints;
+ if (current->used_as_hint) {
+ /* TODO: Avoid most often scratch registers. Find a better way ??? */
+ ZEND_REGSET_INCL(low_priority_regs, ZREG_R0);
+ ZEND_REGSET_INCL(low_priority_regs, ZREG_R1);
+ ZEND_REGSET_INCL(low_priority_regs, ZREG_XMM0);
+ ZEND_REGSET_INCL(low_priority_regs, ZREG_XMM1);
+ }
+
+ ZEND_REGSET_FOREACH(available, i) {
+ if (ZEND_REGSET_IN(low_priority_regs, i)) {
+ if (freeUntilPos[i] > pos2) {
+ reg2 = i;
+ pos2 = freeUntilPos[i];
+ }
+ } else if (freeUntilPos[i] > pos) {
+ reg = i;
+ pos = freeUntilPos[i];
+ }
+ } ZEND_REGSET_FOREACH_END();
+
+ if (reg == ZREG_NONE) {
+ if (reg2 != ZREG_NONE) {
+ reg = reg2;
+ pos = pos2;
+ reg2 = ZREG_NONE;
+ }
+ }
+
+ if (reg == ZREG_NONE) {
+ /* no register available without spilling */
+ return 0;
+ } else if (zend_interval_end(current) < pos) {
+ /* register available for the whole interval */
+ current->reg = reg;
+ if (current->used_as_hint) {
+ ZEND_REGSET_INCL(*hints, reg);
+ }
+ return 1;
+#if 0
+ // TODO: allow low prioirity register usage
+ } else if (reg2 != ZREG_NONE && zend_interval_end(current) < pos2) {
+ /* register available for the whole interval */
+ current->reg = reg2;
+ if (current->used_as_hint) {
+ ZEND_REGSET_INCL(*hints, reg2);
+ }
+ return 1;
+#endif
+ } else {
+ /* TODO: enable interval splitting ??? */
+ /* register available for the first part of the interval */
+ if (1 || zend_jit_split_interval(current, pos, list, free) != SUCCESS) {
+ return 0;
+ }
+ current->reg = reg;
+ if (current->used_as_hint) {
+ ZEND_REGSET_INCL(*hints, reg);
+ }
+ return 1;
+ }
+}
+
+/* See "Optimized Interval Splitting in a Linear Scan Register Allocator",
+ Christian Wimmer VEE'05 (2005), Figure 5. Allocation with spilling.
+ and "Linear Scan Register Allocation on SSA Form", Christian Wimmer and
+ Michael Franz, CGO'10 (2010), Figure 6. */
+static int zend_jit_allocate_blocked_reg(void)
+{
+ /* TODO: ??? */
+ return 0;
+}
+
+/* See "Optimized Interval Splitting in a Linear Scan Register Allocator",
+ Christian Wimmer VEE'10 (2005), Figure 2. */
+static zend_lifetime_interval* zend_jit_linear_scan(const zend_op_array *op_array, zend_ssa *ssa, zend_lifetime_interval *list)
+{
+ zend_lifetime_interval *unhandled, *active, *inactive, *handled, *free;
+ zend_lifetime_interval *current, **p, *q;
+ uint32_t position;
+ zend_regset available = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP);
+ zend_regset hints = ZEND_REGSET_EMPTY;
+
+ unhandled = list;
+ /* active = inactive = handled = free = {} */
+ active = inactive = handled = free = NULL;
+ while (unhandled != NULL) {
+ current = unhandled;
+ unhandled = unhandled->list_next;
+ position = current->range.start;
+
+ p = &active;
+ while (*p) {
+ uint32_t end = zend_interval_end(*p);
+
+ q = *p;
+ if (end < position) {
+ /* move ival from active to handled */
+ ZEND_REGSET_INCL(available, q->reg);
+ *p = q->list_next;
+ q->list_next = handled;
+ handled = q;
+ } else if (!zend_interval_covers(q, position)) {
+ /* move ival from active to inactive */
+ ZEND_REGSET_INCL(available, q->reg);
+ *p = q->list_next;
+ q->list_next = inactive;
+ inactive = q;
+ } else {
+ p = &q->list_next;
+ }
+ }
+
+ p = &inactive;
+ while (*p) {
+ uint32_t end = zend_interval_end(*p);
+
+ q = *p;
+ if (end < position) {
+ /* move ival from inactive to handled */
+ *p = q->list_next;
+ q->list_next = handled;
+ handled = q;
+ } else if (zend_interval_covers(q, position)) {
+ /* move ival from inactive to active */
+ ZEND_REGSET_EXCL(available, q->reg);
+ *p = q->list_next;
+ q->list_next = active;
+ active = q;
+ } else {
+ p = &q->list_next;
+ }
+ }
+
+ if (zend_jit_try_allocate_free_reg(op_array, ssa, current, available, &hints, active, inactive, &unhandled, &free) ||
+ zend_jit_allocate_blocked_reg()) {
+ ZEND_REGSET_EXCL(available, current->reg);
+ current->list_next = active;
+ active = current;
+ } else {
+ current->list_next = free;
+ free = current;
+ }
+ }
+
+ /* move active to handled */
+ while (active) {
+ current = active;
+ active = active->list_next;
+ current->list_next = handled;
+ handled = current;
+ }
+
+ /* move inactive to handled */
+ while (inactive) {
+ current = inactive;
+ inactive = inactive->list_next;
+ current->list_next = handled;
+ handled = current;
+ }
+
+ return handled;
+}
+
+static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array *op_array, zend_ssa *ssa)
+{
+ void *checkpoint;
+ int set_size, candidates_count, i;
+ zend_bitset candidates = NULL;
+ zend_lifetime_interval *list, *ival;
+ zend_lifetime_interval **intervals;
+ ALLOCA_FLAG(use_heap);
+
+ if (!ssa->var_info) {
+ return NULL;
+ }
+
+ /* Identify SSA variables suitable for register allocation */
+ set_size = zend_bitset_len(ssa->vars_count);
+ candidates = ZEND_BITSET_ALLOCA(set_size, use_heap);
+ if (!candidates) {
+ return NULL;
+ }
+ candidates_count = 0;
+ zend_bitset_clear(candidates, set_size);
+ for (i = 0; i < ssa->vars_count; i++) {
+ if (zend_jit_may_be_in_reg(op_array, ssa, i)) {
+ zend_bitset_incl(candidates, i);
+ candidates_count++;
+ }
+ }
+ if (!candidates_count) {
+ free_alloca(candidates, use_heap);
+ return NULL;
+ }
+
+ checkpoint = zend_arena_checkpoint(CG(arena));
+
+ /* Find life-time intervals */
+ if (zend_jit_compute_liveness(op_array, ssa, candidates, &list) != SUCCESS) {
+ goto failure;
+ }
+
+ if (list) {
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_REG_ALLOC) {
+ fprintf(stderr, "Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]");
+ ival = list;
+ while (ival) {
+ zend_life_range *range;
+ int var_num = ssa->vars[ival->ssa_var].var;
+
+ fprintf(stderr, "#%d.", ival->ssa_var);
+ zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
+ fprintf(stderr, ": %u-%u", ival->range.start, ival->range.end);
+ range = ival->range.next;
+ while (range) {
+ fprintf(stderr, ", %u-%u", range->start, range->end);
+ range = range->next;
+ }
+ if (ival->load) {
+ fprintf(stderr, " load");
+ }
+ if (ival->store) {
+ fprintf(stderr, " store");
+ }
+ if (ival->hint) {
+ var_num = ssa->vars[ival->hint->ssa_var].var;
+ fprintf(stderr, " hint=#%d.", ival->hint->ssa_var);
+ zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
+ }
+ fprintf(stderr, "\n");
+ ival = ival->list_next;
+ }
+ fprintf(stderr, "\n");
+ }
+
+ /* Linear Scan Register Allocation */
+ list = zend_jit_linear_scan(op_array, ssa, list);
+
+ if (list) {
+ intervals = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_lifetime_interval*));
+ if (!intervals) {
+ goto failure;
+ }
+
+ ival = list;
+ while (ival != NULL) {
+ zend_lifetime_interval *next = ival->list_next;
+
+ ival->list_next = intervals[ival->ssa_var];
+ intervals[ival->ssa_var] = ival;
+ ival = next;
+ }
+
+ if (zend_jit_reg_alloc >= ZEND_JIT_REG_ALLOC_GLOBAL) {
+ /* Naive SSA resolution */
+ for (i = 0; i < ssa->vars_count; i++) {
+ if (ssa->vars[i].definition_phi && !ssa->vars[i].no_val) {
+ zend_ssa_phi *phi = ssa->vars[i].definition_phi;
+ int k, src;
+
+ if (phi->pi >= 0) {
+ if (!ssa->vars[i].phi_use_chain
+ || ssa->vars[i].phi_use_chain->block != phi->block) {
+ src = phi->sources[0];
+ if (intervals[i]) {
+ if (!intervals[src]) {
+ intervals[i]->load = 1;
+ } else if (intervals[i]->reg != intervals[src]->reg) {
+ intervals[i]->load = 1;
+ intervals[src]->store = 1;
+ }
+ } else if (intervals[src]) {
+ intervals[src]->store = 1;
+ }
+ }
+ } else {
+ int need_move = 0;
+
+ for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
+ src = phi->sources[k];
+ if (src >= 0) {
+ if (ssa->vars[src].definition_phi
+ && ssa->vars[src].definition_phi->pi >= 0
+ && phi->block == ssa->vars[src].definition_phi->block) {
+ /* Skip zero-lenght interval for Pi variable */
+ src = ssa->vars[src].definition_phi->sources[0];
+ }
+ if (intervals[i]) {
+ if (!intervals[src]) {
+ need_move = 1;
+ } else if (intervals[i]->reg != intervals[src]->reg) {
+ need_move = 1;
+ }
+ } else if (intervals[src]) {
+ need_move = 1;
+ }
+ }
+ }
+ if (need_move) {
+ if (intervals[i]) {
+ intervals[i]->load = 1;
+ }
+ for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
+ src = phi->sources[k];
+ if (src >= 0) {
+ if (ssa->vars[src].definition_phi
+ && ssa->vars[src].definition_phi->pi >= 0
+ && phi->block == ssa->vars[src].definition_phi->block) {
+ /* Skip zero-lenght interval for Pi variable */
+ src = ssa->vars[src].definition_phi->sources[0];
+ }
+ if (intervals[src]) {
+ intervals[src]->store = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Remove useless register allocation */
+ for (i = 0; i < ssa->vars_count; i++) {
+ if (intervals[i] &&
+ (intervals[i]->load ||
+ (intervals[i]->store && ssa->vars[i].definition >= 0)) &&
+ ssa->vars[i].use_chain < 0) {
+ zend_bool may_remove = 1;
+ zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
+
+ while (phi) {
+ if (intervals[phi->ssa_var] &&
+ !intervals[phi->ssa_var]->load) {
+ may_remove = 0;
+ break;
+ }
+ phi = zend_ssa_next_use_phi(ssa, i, phi);
+ }
+ if (may_remove) {
+ intervals[i] = NULL;
+ }
+ }
+ }
+ /* Remove intervals used once */
+ for (i = 0; i < ssa->vars_count; i++) {
+ if (intervals[i] &&
+ intervals[i]->load &&
+ intervals[i]->store &&
+ (ssa->vars[i].use_chain < 0 ||
+ zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
+ zend_bool may_remove = 1;
+ zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
+
+ while (phi) {
+ if (intervals[phi->ssa_var] &&
+ !intervals[phi->ssa_var]->load) {
+ may_remove = 0;
+ break;
+ }
+ phi = zend_ssa_next_use_phi(ssa, i, phi);
+ }
+ if (may_remove) {
+ intervals[i] = NULL;
+ }
+ }
+ }
+ }
+
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_REG_ALLOC) {
+ fprintf(stderr, "Allocated Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]");
+ for (i = 0; i < ssa->vars_count; i++) {
+ ival = intervals[i];
+ while (ival) {
+ zend_life_range *range;
+ int var_num = ssa->vars[ival->ssa_var].var;
+
+ fprintf(stderr, "#%d.", ival->ssa_var);
+ zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
+ fprintf(stderr, ": %u-%u", ival->range.start, ival->range.end);
+ range = ival->range.next;
+ while (range) {
+ fprintf(stderr, ", %u-%u", range->start, range->end);
+ range = range->next;
+ }
+ fprintf(stderr, " (%s)", zend_reg_name[ival->reg]);
+ if (ival->load) {
+ fprintf(stderr, " load");
+ }
+ if (ival->store) {
+ fprintf(stderr, " store");
+ }
+ if (ival->hint) {
+ var_num = ssa->vars[ival->hint->ssa_var].var;
+ fprintf(stderr, " hint=#%d.", ival->hint->ssa_var);
+ zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
+ if (ival->hint->reg != ZREG_NONE) {
+ fprintf(stderr, " (%s)", zend_reg_name[ival->hint->reg]);
+ }
+ }
+ fprintf(stderr, "\n");
+ ival = ival->list_next;
+ }
+ }
+ fprintf(stderr, "\n");
+ }
+
+ free_alloca(candidates, use_heap);
+ return intervals;
+ }
+ }
+
+failure:
+ zend_arena_release(&CG(arena), checkpoint);
+ free_alloca(candidates, use_heap);
+ return NULL;
+}
+
+static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_opline)
+{
+ int b, i, end;
+ zend_op *opline;
+ dasm_State* dasm_state = NULL;
+ void *handler;
+ int call_level = 0;
+ void *checkpoint = NULL;
+ zend_lifetime_interval **ra = NULL;
+ zend_bool is_terminated = 1; /* previous basic block is terminated by jump */
+ zend_bool recv_emitted = 0; /* emitted at least one RECV opcode */
+ zend_uchar smart_branch_opcode;
+ uint32_t target_label, target_label2;
+ uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info;
+ zend_bool send_result;
+ zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
+ zend_class_entry *ce;
+
+ if (ZCG(accel_directives).jit_bisect_limit) {
+ jit_bisect_pos++;
+ if (jit_bisect_pos >= ZCG(accel_directives).jit_bisect_limit) {
+ if (jit_bisect_pos == ZCG(accel_directives).jit_bisect_limit) {
+ fprintf(stderr, "Not JITing %s%s%s in %s:%d and after due to jit_bisect_limit\n",
+ op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
+ op_array->scope ? "::" : "",
+ op_array->function_name ? ZSTR_VAL(op_array->function_name) : "{main}",
+ ZSTR_VAL(op_array->filename), op_array->line_start);
+ }
+ return FAILURE;
+ }
+ }
+
+ if (zend_jit_reg_alloc) {
+ checkpoint = zend_arena_checkpoint(CG(arena));
+ ra = zend_jit_allocate_registers(op_array, ssa);
+ }
+
+ /* mark hidden branch targets */
+ for (b = 0; b < ssa->cfg.blocks_count; b++) {
+ if (ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE &&
+ ssa->cfg.blocks[b].len > 1) {
+
+ opline = op_array->opcodes + ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1;
+ if (opline->opcode == ZEND_DO_FCALL &&
+ (opline-1)->opcode == ZEND_NEW) {
+ ssa->cfg.blocks[ssa->cfg.blocks[b].successors[0]].flags |= ZEND_BB_TARGET;
+ }
+ }
+ }
+
+ dasm_init(&dasm_state, DASM_MAXSECTION);
+ dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
+ dasm_setup(&dasm_state, dasm_actions);
+
+ dasm_growpc(&dasm_state, ssa->cfg.blocks_count * 2 + 1);
+
+ zend_jit_align_func(&dasm_state);
+ for (b = 0; b < ssa->cfg.blocks_count; b++) {
+ if ((ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE) == 0) {
+ continue;
+ }
+//#ifndef CONTEXT_THREADED_JIT
+ if (ssa->cfg.blocks[b].flags & ZEND_BB_ENTRY) {
+ if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) {
+ /* pass */
+ } else if (zend_jit_level < ZEND_JIT_LEVEL_INLINE &&
+ ssa->cfg.blocks[b].len == 1 &&
+ (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT) &&
+ op_array->opcodes[ssa->cfg.blocks[b].start].opcode != ZEND_JMP) {
+ /* don't generate code for BB with single opcode */
+ continue;
+ }
+ if (ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW) {
+ if (!is_terminated) {
+ zend_jit_jmp(&dasm_state, b);
+ }
+ }
+ zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
+ zend_jit_prologue(&dasm_state);
+ } else
+//#endif
+ if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) {
+ opline = op_array->opcodes + ssa->cfg.blocks[b].start;
+ if (ssa->cfg.flags & ZEND_CFG_RECV_ENTRY) {
+ if (opline->opcode == ZEND_RECV_INIT) {
+ if (opline == op_array->opcodes ||
+ (opline-1)->opcode != ZEND_RECV_INIT) {
+ if (recv_emitted) {
+ zend_jit_jmp(&dasm_state, b);
+ }
+ zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
+ for (i = 1; (opline+i)->opcode == ZEND_RECV_INIT; i++) {
+ zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b + i);
+ }
+ zend_jit_prologue(&dasm_state);
+ }
+ recv_emitted = 1;
+ } else if (opline->opcode == ZEND_RECV) {
+ if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
+ /* skip */
+ continue;
+ } else if (recv_emitted) {
+ zend_jit_jmp(&dasm_state, b);
+ zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
+ zend_jit_prologue(&dasm_state);
+ } else {
+ zend_arg_info *arg_info;
+
+ if (opline->op1.num <= op_array->num_args) {
+ arg_info = &op_array->arg_info[opline->op1.num - 1];
+ } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+ arg_info = &op_array->arg_info[op_array->num_args];
+ } else {
+ /* skip */
+ continue;
+ }
+ if (!ZEND_TYPE_IS_SET(arg_info->type)) {
+ /* skip */
+ continue;
+ }
+ zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
+ zend_jit_prologue(&dasm_state);
+ recv_emitted = 1;
+ }
+ } else {
+ if (recv_emitted) {
+ zend_jit_jmp(&dasm_state, b);
+ } else if (zend_jit_level < ZEND_JIT_LEVEL_INLINE &&
+ ssa->cfg.blocks[b].len == 1 &&
+ (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
+ /* don't generate code for BB with single opcode */
+ dasm_free(&dasm_state);
+
+ if (zend_jit_reg_alloc) {
+ zend_arena_release(&CG(arena), checkpoint);
+ }
+ return SUCCESS;
+ }
+ zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
+ zend_jit_prologue(&dasm_state);
+ recv_emitted = 1;
+ }
+ } else if (zend_jit_level < ZEND_JIT_LEVEL_INLINE &&
+ ssa->cfg.blocks[b].len == 1 &&
+ (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
+ /* don't generate code for BB with single opcode */
+ dasm_free(&dasm_state);
+
+ if (zend_jit_reg_alloc) {
+ zend_arena_release(&CG(arena), checkpoint);
+ }
+ return SUCCESS;
+ } else {
+ zend_jit_label(&dasm_state, ssa->cfg.blocks_count + b);
+ zend_jit_prologue(&dasm_state);
+ }
+ }
+
+ is_terminated = 0;
+
+ zend_jit_label(&dasm_state, b);
+ if (zend_jit_level < ZEND_JIT_LEVEL_INLINE) {
+ if ((ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW)
+ && ssa->cfg.blocks[b].start != 0
+ && (op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_NOP
+ || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_LONG
+ || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING)) {
+ if (!zend_jit_reset_opline(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)
+ || !zend_jit_set_valid_ip(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)) {
+ goto jit_failure;
+ }
+ } else {
+ if (!zend_jit_set_opline(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)) {
+ goto jit_failure;
+ }
+ }
+ } else if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) {
+ if (!zend_jit_reset_opline(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)) {
+ goto jit_failure;
+ }
+ } else if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY|ZEND_BB_ENTRY)) {
+ if (!zend_jit_set_opline(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)) {
+ goto jit_failure;
+ }
+ }
+ if (ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) {
+ if (!zend_jit_check_timeout(&dasm_state, op_array->opcodes + ssa->cfg.blocks[b].start)) {
+ goto jit_failure;
+ }
+ }
+ if (!ssa->cfg.blocks[b].len) {
+ continue;
+ }
+ if ((zend_jit_reg_alloc >= ZEND_JIT_REG_ALLOC_GLOBAL) && ra) {
+ zend_ssa_phi *phi = ssa->blocks[b].phis;
+
+ while (phi) {
+ zend_lifetime_interval *ival = ra[phi->ssa_var];
+
+ if (ival) {
+ if (ival->load) {
+ ZEND_ASSERT(ival->reg != ZREG_NONE);
+
+ if (!zend_jit_load_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg)) {
+ goto jit_failure;
+ }
+ } else if (ival->store) {
+ ZEND_ASSERT(ival->reg != ZREG_NONE);
+
+ if (!zend_jit_store_var(&dasm_state, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg)) {
+ goto jit_failure;
+ }
+ }
+ }
+ phi = phi->next;
+ }
+ }
+ end = ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1;
+ for (i = ssa->cfg.blocks[b].start; i <= end; i++) {
+ opline = op_array->opcodes + i;
+ switch (opline->opcode) {
+ case ZEND_INIT_FCALL:
+ case ZEND_INIT_FCALL_BY_NAME:
+ case ZEND_INIT_NS_FCALL_BY_NAME:
+ case ZEND_INIT_METHOD_CALL:
+ case ZEND_INIT_DYNAMIC_CALL:
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ case ZEND_INIT_USER_CALL:
+ case ZEND_NEW:
+ call_level++;
+ }
+
+ if (zend_jit_level >= ZEND_JIT_LEVEL_INLINE) {
+ switch (opline->opcode) {
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ if (opline->op1_type != IS_CV) {
+ break;
+ }
+ op1_info = OP1_INFO();
+ if (!(op1_info & MAY_BE_LONG)) {
+ break;
+ }
+ if (opline->result_type != IS_UNUSED) {
+ res_use_info = RES_USE_INFO();
+ res_info = RES_INFO();
+ res_addr = RES_REG_ADDR();
+ } else {
+ res_use_info = -1;
+ res_info = -1;
+ res_addr = 0;
+ }
+ op1_def_info = OP1_DEF_INFO();
+ if (!zend_jit_inc_dec(&dasm_state, opline, op_array,
+ op1_info, OP1_REG_ADDR(),
+ op1_def_info, OP1_DEF_REG_ADDR(),
+ res_use_info, res_info,
+ res_addr,
+ (op1_def_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ case ZEND_SL:
+ case ZEND_SR:
+ case ZEND_MOD:
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
+ break;
+ }
+ if (!(op1_info & MAY_BE_LONG)
+ || !(op2_info & MAY_BE_LONG)) {
+ break;
+ }
+ if (opline->result_type == IS_TMP_VAR
+ && (i + 1) <= end
+ && (opline+1)->opcode == ZEND_SEND_VAL
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ send_result = 1;
+ res_use_info = -1;
+ res_addr = 0; /* set inside backend */
+ } else {
+ send_result = 0;
+ res_use_info = RES_USE_INFO();
+ res_addr = RES_REG_ADDR();
+ }
+ if (!zend_jit_long_math(&dasm_state, opline, op_array,
+ op1_info, OP1_RANGE(), OP1_REG_ADDR(),
+ op2_info, OP2_RANGE(), OP2_REG_ADDR(),
+ res_use_info, RES_INFO(), res_addr,
+ send_result,
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+// case ZEND_DIV: // TODO: check for division by zero ???
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
+ break;
+ }
+ if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
+ !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ break;
+ }
+ if (opline->result_type == IS_TMP_VAR
+ && (i + 1) <= end
+ && (opline+1)->opcode == ZEND_SEND_VAL
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ send_result = 1;
+ res_use_info = -1;
+ res_addr = 0; /* set inside backend */
+ } else {
+ send_result = 0;
+ res_use_info = RES_USE_INFO();
+ res_addr = RES_REG_ADDR();
+ }
+ res_info = RES_INFO();
+ if (!zend_jit_math(&dasm_state, opline, op_array,
+ op1_info, OP1_REG_ADDR(),
+ op2_info, OP2_REG_ADDR(),
+ res_use_info, res_info, res_addr,
+ send_result,
+ (res_info & MAY_BE_LONG) && (res_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, op_array, ssa),
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_CONCAT:
+ case ZEND_FAST_CONCAT:
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
+ break;
+ }
+ if (!(op1_info & MAY_BE_STRING) ||
+ !(op2_info & MAY_BE_STRING)) {
+ break;
+ }
+ if (opline->result_type == IS_TMP_VAR
+ && (i + 1) <= end
+ && (opline+1)->opcode == ZEND_SEND_VAL
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ send_result = 1;
+ } else {
+ send_result = 0;
+ }
+ if (!zend_jit_concat(&dasm_state, opline, op_array,
+ op1_info, op2_info, RES_INFO(), send_result,
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_ASSIGN_OP:
+ if (opline->extended_value == ZEND_POW
+ || opline->extended_value == ZEND_DIV) {
+ // TODO: check for division by zero ???
+ break;
+ }
+ if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
+ break;
+ }
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
+ break;
+ }
+ if (opline->extended_value == ZEND_ADD
+ || opline->extended_value == ZEND_SUB
+ || opline->extended_value == ZEND_MUL
+ || opline->extended_value == ZEND_DIV) {
+ if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
+ || !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ break;
+ }
+ } else if (opline->extended_value == ZEND_BW_OR
+ || opline->extended_value == ZEND_BW_AND
+ || opline->extended_value == ZEND_BW_XOR
+ || opline->extended_value == ZEND_SL
+ || opline->extended_value == ZEND_SR
+ || opline->extended_value == ZEND_MOD) {
+ if (!(op1_info & MAY_BE_LONG)
+ || !(op2_info & MAY_BE_LONG)) {
+ break;
+ }
+ } else if (opline->extended_value == ZEND_CONCAT) {
+ if (!(op1_info & MAY_BE_STRING)
+ || !(op2_info & MAY_BE_STRING)) {
+ break;
+ }
+ }
+ op1_def_info = OP1_DEF_INFO();
+ if (!zend_jit_assign_op(&dasm_state, opline, op_array,
+ op1_info, op1_def_info, OP1_RANGE(),
+ op2_info, OP2_RANGE(),
+ (op1_def_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, op_array, ssa),
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_ASSIGN_DIM_OP:
+ if (opline->extended_value == ZEND_POW
+ || opline->extended_value == ZEND_DIV) {
+ // TODO: check for division by zero ???
+ break;
+ }
+ if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
+ break;
+ }
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ if (!zend_jit_assign_dim_op(&dasm_state, opline, op_array,
+ OP1_INFO(), OP1_DEF_INFO(), OP2_INFO(),
+ OP1_DATA_INFO(), OP1_DATA_RANGE(),
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_ASSIGN_DIM:
+ if (opline->op1_type != IS_CV) {
+ break;
+ }
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ if (!zend_jit_assign_dim(&dasm_state, opline, op_array,
+ OP1_INFO(), OP2_INFO(), OP1_DATA_INFO(),
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_ASSIGN:
+ if (opline->op1_type != IS_CV) {
+ break;
+ }
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ if (opline->result_type == IS_UNUSED) {
+ res_addr = 0;
+ res_info = -1;
+ } else {
+ res_addr = RES_REG_ADDR();
+ res_info = RES_INFO();
+ }
+ op2_addr = OP2_REG_ADDR();
+ if (ra
+ && ssa->ops[opline - op_array->opcodes].op2_def >= 0
+ && !ssa->vars[ssa->ops[opline - op_array->opcodes].op2_def].no_val) {
+ op2_def_addr = OP2_DEF_REG_ADDR();
+ } else {
+ op2_def_addr = op2_addr;
+ }
+ if (!zend_jit_assign(&dasm_state, opline, op_array,
+ OP1_INFO(), OP1_REG_ADDR(),
+ OP1_DEF_INFO(), OP1_DEF_REG_ADDR(),
+ OP2_INFO(), op2_addr, op2_def_addr,
+ res_info, res_addr,
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_QM_ASSIGN:
+ op1_addr = OP1_REG_ADDR();
+ if (ra
+ && ssa->ops[opline - op_array->opcodes].op1_def >= 0
+ && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
+ op1_def_addr = OP1_DEF_REG_ADDR();
+ } else {
+ op1_def_addr = op1_addr;
+ }
+ if (!zend_jit_qm_assign(&dasm_state, opline, op_array,
+ OP1_INFO(), op1_addr, op1_def_addr,
+ RES_INFO(), RES_REG_ADDR())) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_INIT_FCALL:
+ case ZEND_INIT_FCALL_BY_NAME:
+ if (!zend_jit_init_fcall(&dasm_state, opline, b, op_array, ssa, call_level)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_SEND_VAL:
+ case ZEND_SEND_VAL_EX:
+ if (opline->opcode == ZEND_SEND_VAL_EX
+ && opline->op2.num > MAX_ARG_FLAG_NUM) {
+ break;
+ }
+ if (!zend_jit_send_val(&dasm_state, opline, op_array,
+ OP1_INFO(), OP1_REG_ADDR())) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_SEND_REF:
+ if (!zend_jit_send_ref(&dasm_state, opline, op_array,
+ OP1_INFO(), 0)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_SEND_VAR:
+ case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_VAR_NO_REF:
+ case ZEND_SEND_VAR_NO_REF_EX:
+ if ((opline->opcode == ZEND_SEND_VAR_EX
+ || opline->opcode == ZEND_SEND_VAR_NO_REF_EX)
+ && opline->op2.num > MAX_ARG_FLAG_NUM) {
+ break;
+ }
+ op1_addr = OP1_REG_ADDR();
+ if (ra
+ && ssa->ops[opline - op_array->opcodes].op1_def >= 0
+ && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
+ op1_def_addr = OP1_DEF_REG_ADDR();
+ } else {
+ op1_def_addr = op1_addr;
+ }
+ if (!zend_jit_send_var(&dasm_state, opline, op_array,
+ OP1_INFO(), op1_addr, op1_def_addr)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_DO_UCALL:
+ is_terminated = 1;
+ /* break missing intentionally */
+ case ZEND_DO_ICALL:
+ case ZEND_DO_FCALL_BY_NAME:
+ case ZEND_DO_FCALL:
+ if (!zend_jit_do_fcall(&dasm_state, opline, op_array, ssa, call_level, b + 1)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_SMALLER:
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_CASE:
+ if ((opline->result_type & IS_TMP_VAR)
+ && (i + 1) <= end
+ && ((opline+1)->opcode == ZEND_JMPZ
+ || (opline+1)->opcode == ZEND_JMPNZ
+ || (opline+1)->opcode == ZEND_JMPZ_EX
+ || (opline+1)->opcode == ZEND_JMPNZ_EX
+ || (opline+1)->opcode == ZEND_JMPZNZ)
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ smart_branch_opcode = (opline+1)->opcode;
+ target_label = ssa->cfg.blocks[b].successors[0];
+ target_label2 = ssa->cfg.blocks[b].successors[1];
+ } else {
+ smart_branch_opcode = 0;
+ target_label = target_label2 = (uint32_t)-1;
+ }
+ if (!zend_jit_cmp(&dasm_state, opline, op_array,
+ OP1_INFO(), OP1_REG_ADDR(),
+ OP2_INFO(), OP2_REG_ADDR(),
+ RES_REG_ADDR(),
+ zend_may_throw(opline, op_array, ssa),
+ smart_branch_opcode, target_label, target_label2)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_IS_IDENTICAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ if ((opline->result_type & IS_TMP_VAR)
+ && (i + 1) <= end
+ && ((opline+1)->opcode == ZEND_JMPZ
+ || (opline+1)->opcode == ZEND_JMPNZ
+ || (opline+1)->opcode == ZEND_JMPZNZ)
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ smart_branch_opcode = (opline+1)->opcode;
+ target_label = ssa->cfg.blocks[b].successors[0];
+ target_label2 = ssa->cfg.blocks[b].successors[1];
+ } else {
+ smart_branch_opcode = 0;
+ target_label = target_label2 = (uint32_t)-1;
+ }
+ if (!zend_jit_identical(&dasm_state, opline, op_array,
+ OP1_INFO(), OP1_REG_ADDR(),
+ OP2_INFO(), OP2_REG_ADDR(),
+ RES_REG_ADDR(),
+ zend_may_throw(opline, op_array, ssa),
+ smart_branch_opcode, target_label, target_label2)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_DEFINED:
+ if ((opline->result_type & IS_TMP_VAR)
+ && (i + 1) <= end
+ && ((opline+1)->opcode == ZEND_JMPZ
+ || (opline+1)->opcode == ZEND_JMPNZ
+ || (opline+1)->opcode == ZEND_JMPZNZ)
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ smart_branch_opcode = (opline+1)->opcode;
+ target_label = ssa->cfg.blocks[b].successors[0];
+ target_label2 = ssa->cfg.blocks[b].successors[1];
+ } else {
+ smart_branch_opcode = 0;
+ target_label = target_label2 = (uint32_t)-1;
+ }
+ if (!zend_jit_defined(&dasm_state, opline, op_array, smart_branch_opcode, target_label, target_label2)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_TYPE_CHECK:
+ if (opline->extended_value == MAY_BE_RESOURCE) {
+ // TODO: support for is_resource() ???
+ break;
+ }
+ if ((opline->result_type & IS_TMP_VAR)
+ && (i + 1) <= end
+ && ((opline+1)->opcode == ZEND_JMPZ
+ || (opline+1)->opcode == ZEND_JMPNZ
+ || (opline+1)->opcode == ZEND_JMPZNZ)
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ smart_branch_opcode = (opline+1)->opcode;
+ target_label = ssa->cfg.blocks[b].successors[0];
+ target_label2 = ssa->cfg.blocks[b].successors[1];
+ } else {
+ smart_branch_opcode = 0;
+ target_label = target_label2 = (uint32_t)-1;
+ }
+ if (!zend_jit_type_check(&dasm_state, opline, op_array, OP1_INFO(), smart_branch_opcode, target_label, target_label2)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_RETURN:
+ op1_info = OP1_INFO();
+ if ((PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info))
+ || op_array->type == ZEND_EVAL_CODE
+ // TODO: support for top-level code
+ || !op_array->function_name
+ // TODO: support for IS_UNDEF ???
+ || (op1_info & MAY_BE_UNDEF)) {
+ if (!zend_jit_tail_handler(&dasm_state, opline)) {
+ goto jit_failure;
+ }
+ } else if (!zend_jit_return(&dasm_state, opline, op_array, ssa,
+ op1_info, OP1_REG_ADDR())) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_BOOL:
+ case ZEND_BOOL_NOT:
+ if (!zend_jit_bool_jmpznz(&dasm_state, opline, op_array,
+ OP1_INFO(), OP1_REG_ADDR(), RES_REG_ADDR(),
+ -1, -1,
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ if (opline > op_array->opcodes + ssa->cfg.blocks[b].start &&
+ ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
+ /* smart branch */
+ if (!zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
+ goto jit_failure;
+ }
+ goto done;
+ }
+ /* break missing intentionally */
+ case ZEND_JMPZNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ if (opline->result_type == IS_UNDEF) {
+ res_addr = 0;
+ } else {
+ res_addr = RES_REG_ADDR();
+ }
+ if (!zend_jit_bool_jmpznz(&dasm_state, opline, op_array,
+ OP1_INFO(), OP1_REG_ADDR(), res_addr,
+ ssa->cfg.blocks[b].successors[0], ssa->cfg.blocks[b].successors[1],
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_FETCH_DIM_R:
+ case ZEND_FETCH_DIM_IS:
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ if (!zend_jit_fetch_dim_read(&dasm_state, opline, op_array,
+ OP1_INFO(), OP2_INFO(), RES_INFO(),
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_ISSET_ISEMPTY_DIM_OBJ:
+ if ((opline->extended_value & ZEND_ISEMPTY)) {
+ // TODO: support for empty() ???
+ break;
+ }
+ if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
+ break;
+ }
+ if ((opline->result_type & IS_TMP_VAR)
+ && (i + 1) <= end
+ && ((opline+1)->opcode == ZEND_JMPZ
+ || (opline+1)->opcode == ZEND_JMPNZ
+ || (opline+1)->opcode == ZEND_JMPZNZ)
+ && (opline+1)->op1_type == IS_TMP_VAR
+ && (opline+1)->op1.var == opline->result.var) {
+ i++;
+ smart_branch_opcode = (opline+1)->opcode;
+ target_label = ssa->cfg.blocks[b].successors[0];
+ target_label2 = ssa->cfg.blocks[b].successors[1];
+ } else {
+ smart_branch_opcode = 0;
+ target_label = target_label2 = (uint32_t)-1;
+ }
+ if (!zend_jit_isset_isempty_dim(&dasm_state, opline, op_array,
+ OP1_INFO(), OP2_INFO(),
+ zend_may_throw(opline, op_array, ssa),
+ smart_branch_opcode, target_label, target_label2)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_FETCH_OBJ_R:
+ case ZEND_FETCH_OBJ_IS:
+ if (opline->op2_type != IS_CONST
+ || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
+ || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
+ break;
+ }
+ ce = NULL;
+ if (opline->op1_type == IS_UNUSED) {
+ op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
+ ce = op_array->scope;
+ } else {
+ op1_info = OP1_INFO();
+ if (ssa->var_info && ssa->ops) {
+ zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
+ if (ssa_op->op1_use >= 0) {
+ zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
+ if (op1_ssa->ce && !op1_ssa->is_instanceof && !op1_ssa->ce->create_object) {
+ ce = op1_ssa->ce;
+ }
+ }
+ }
+ }
+ if (!(op1_info & MAY_BE_OBJECT)) {
+ break;
+ }
+ if (!zend_jit_fetch_obj_read(&dasm_state, opline, op_array,
+ op1_info, ce,
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_BIND_GLOBAL:
+ if (!ssa->ops || !ssa->var_info) {
+ op1_info = MAY_BE_ANY|MAY_BE_REF;
+ } else {
+ op1_info = OP1_INFO();
+ }
+ if (!zend_jit_bind_global(&dasm_state, opline, op_array, op1_info)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_RECV:
+ if (!zend_jit_recv(&dasm_state, opline, op_array)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_RECV_INIT:
+ if (!zend_jit_recv_init(&dasm_state, opline, op_array,
+ (opline + 1)->opcode != ZEND_RECV_INIT,
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_FREE:
+ case ZEND_FE_FREE:
+ if (!zend_jit_free(&dasm_state, opline, op_array, OP1_INFO(),
+ zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_ECHO:
+ if (opline->op1_type != IS_CONST
+ || Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) != IS_STRING) {
+ break;
+ }
+ if (!zend_jit_echo(&dasm_state, opline, op_array)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_SWITCH_LONG:
+ case ZEND_SWITCH_STRING:
+ if (!zend_jit_switch(&dasm_state, opline, op_array, ssa)) {
+ goto jit_failure;
+ }
+ goto done;
+ case ZEND_VERIFY_RETURN_TYPE:
+ if (opline->op1_type == IS_UNUSED) {
+ /* Always throws */
+ break;
+ }
+ if (opline->op1_type == IS_CONST) {
+ /* TODO Different instruction format, has return value */
+ break;
+ }
+ if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Not worth bothering with */
+ break;
+ }
+ if (OP1_INFO() & MAY_BE_REF) {
+ /* TODO May need reference unwrapping. */
+ break;
+ }
+ if (!zend_jit_verify_return_type(&dasm_state, opline, op_array, OP1_INFO())) {
+ goto jit_failure;
+ }
+ goto done;
+ default:
+ break;
+ }
+ }
+
+ switch (opline->opcode) {
+ case ZEND_RECV_INIT:
+ case ZEND_BIND_GLOBAL:
+ if (opline == op_array->opcodes ||
+ opline->opcode != op_array->opcodes[i-1].opcode) {
+ /* repeatable opcodes */
+ if (!zend_jit_handler(&dasm_state, opline, zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ }
+ zend_jit_set_opline(&dasm_state, opline+1);
+ break;
+ case ZEND_NOP:
+ case ZEND_OP_DATA:
+ case ZEND_SWITCH_LONG:
+ case ZEND_SWITCH_STRING:
+ break;
+ case ZEND_JMP:
+ if (zend_jit_level < ZEND_JIT_LEVEL_INLINE) {
+ const zend_op *target = OP_JMP_ADDR(opline, opline->op1);
+
+ if (!zend_jit_set_ip(&dasm_state, target)) {
+ goto jit_failure;
+ }
+ }
+ if (!zend_jit_jmp(&dasm_state, ssa->cfg.blocks[b].successors[0])) {
+ goto jit_failure;
+ }
+ is_terminated = 1;
+ break;
+ case ZEND_CATCH:
+ case ZEND_FAST_CALL:
+ case ZEND_FAST_RET:
+ case ZEND_GENERATOR_CREATE:
+ case ZEND_GENERATOR_RETURN:
+ case ZEND_RETURN_BY_REF:
+ case ZEND_RETURN:
+ case ZEND_EXIT:
+ /* switch through trampoline */
+ case ZEND_YIELD:
+ case ZEND_YIELD_FROM:
+ if (!zend_jit_tail_handler(&dasm_state, opline)) {
+ goto jit_failure;
+ }
+ is_terminated = 1;
+ break;
+ /* stackless execution */
+ case ZEND_INCLUDE_OR_EVAL:
+ case ZEND_DO_FCALL:
+ case ZEND_DO_UCALL:
+ case ZEND_DO_FCALL_BY_NAME:
+ if (!zend_jit_call(&dasm_state, opline, b + 1)) {
+ goto jit_failure;
+ }
+ is_terminated = 1;
+ break;
+ case ZEND_JMPZNZ:
+ if (!zend_jit_handler(&dasm_state, opline, zend_may_throw(opline, op_array, ssa)) ||
+ !zend_jit_cond_jmp(&dasm_state, OP_JMP_ADDR(opline, opline->op2), ssa->cfg.blocks[b].successors[1]) ||
+ !zend_jit_jmp(&dasm_state, ssa->cfg.blocks[b].successors[0])) {
+ goto jit_failure;
+ }
+ is_terminated = 1;
+ break;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ if (opline > op_array->opcodes &&
+ ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
+ /* smart branch */
+ if (!zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
+ goto jit_failure;
+ }
+ goto done;
+ }
+ /* break missing intentionally */
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_ASSERT_CHECK:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ if (!zend_jit_handler(&dasm_state, opline, zend_may_throw(opline, op_array, ssa)) ||
+ !zend_jit_cond_jmp(&dasm_state, opline + 1, ssa->cfg.blocks[b].successors[0])) {
+ goto jit_failure;
+ }
+ break;
+ case ZEND_NEW:
+ if (!zend_jit_handler(&dasm_state, opline, 1)) {
+ return 0;
+ }
+ if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
+ zend_class_entry *ce = NULL;
+
+ if (zend_jit_level >= ZEND_JIT_LEVEL_OPT_FUNC) {
+ if (ssa->ops && ssa->var_info) {
+ zend_ssa_var_info *res_ssa = &ssa->var_info[ssa->ops[opline - op_array->opcodes].result_def];
+ if (res_ssa->ce && !res_ssa->is_instanceof) {
+ ce = res_ssa->ce;
+ }
+ }
+ } else {
+ if (opline->op1_type == IS_CONST) {
+ zval *zv = RT_CONSTANT(opline, opline->op1);
+ if (Z_TYPE_P(zv) == IS_STRING) {
+ zval *lc = zv + 1;
+ ce = (zend_class_entry*)zend_hash_find_ptr(EG(class_table), Z_STR_P(lc));
+ }
+ }
+ }
+
+ i++;
+
+ if (!ce || !(ce->ce_flags & ZEND_ACC_LINKED) || ce->constructor) {
+ const zend_op *next_opline = opline + 1;
+
+ zend_jit_cond_jmp(&dasm_state, next_opline, ssa->cfg.blocks[b].successors[0]);
+ if (zend_jit_level < ZEND_JIT_LEVEL_INLINE) {
+ zend_jit_call(&dasm_state, next_opline, b + 1);
+ is_terminated = 1;
+ } else {
+ zend_jit_do_fcall(&dasm_state, next_opline, op_array, ssa, call_level, b + 1);
+ }
+ }
+ }
+ break;
+ default:
+ if (!zend_jit_handler(&dasm_state, opline, zend_may_throw(opline, op_array, ssa))) {
+ goto jit_failure;
+ }
+ }
+done:
+ switch (opline->opcode) {
+ case ZEND_DO_FCALL:
+ case ZEND_DO_ICALL:
+ case ZEND_DO_UCALL:
+ case ZEND_DO_FCALL_BY_NAME:
+ call_level--;
+ }
+ }
+ }
+
+ handler = dasm_link_and_encode(&dasm_state, op_array, ssa, rt_opline, ra, NULL);
+ if (!handler) {
+ goto jit_failure;
+ }
+ dasm_free(&dasm_state);
+
+ if (zend_jit_reg_alloc) {
+ zend_arena_release(&CG(arena), checkpoint);
+ }
+ return SUCCESS;
+
+jit_failure:
+ if (dasm_state) {
+ dasm_free(&dasm_state);
+ }
+ if (zend_jit_reg_alloc) {
+ zend_arena_release(&CG(arena), checkpoint);
+ }
+ return FAILURE;
+}
+
+static int zend_jit_collect_calls(zend_op_array *op_array, zend_script *script)
+{
+ zend_func_info *func_info =
+ zend_arena_calloc(&CG(arena), 1, sizeof(zend_func_info));
+
+ ZEND_SET_FUNC_INFO(op_array, func_info);
+ func_info->num_args = -1;
+ func_info->return_value_used = -1;
+ return zend_analyze_calls(&CG(arena), script, ZEND_CALL_TREE, op_array, func_info);
+}
+
+static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, const zend_op *rt_opline)
+{
+ zend_ssa ssa;
+ void *checkpoint;
+ zend_func_info *func_info;
+
+ if (*dasm_ptr == dasm_end) {
+ return FAILURE;
+ }
+
+ checkpoint = zend_arena_checkpoint(CG(arena));
+
+ /* Build SSA */
+ memset(&ssa, 0, sizeof(zend_ssa));
+
+ if (zend_jit_op_array_analyze1(op_array, script, &ssa) != SUCCESS) {
+ goto jit_failure;
+ }
+
+ if (zend_jit_level >= ZEND_JIT_LEVEL_OPT_FUNCS) {
+ if (zend_jit_collect_calls(op_array, script) != SUCCESS) {
+ ZEND_SET_FUNC_INFO(op_array, NULL);
+ goto jit_failure;
+ }
+ func_info = ZEND_FUNC_INFO(op_array);
+ func_info->call_map = zend_build_call_map(&CG(arena), func_info, op_array);
+ if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ zend_init_func_return_info(op_array, script, &func_info->return_info);
+ }
+ }
+
+ if (zend_jit_op_array_analyze2(op_array, script, &ssa) != SUCCESS) {
+ goto jit_failure;
+ }
+
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_SSA) {
+ zend_dump_op_array(op_array, ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &ssa);
+ }
+
+ if (zend_jit(op_array, &ssa, rt_opline) != SUCCESS) {
+ goto jit_failure;
+ }
+
+ if (zend_jit_level >= ZEND_JIT_LEVEL_OPT_FUNCS) {
+ ZEND_SET_FUNC_INFO(op_array, NULL);
+ }
+
+ zend_arena_release(&CG(arena), checkpoint);
+ return SUCCESS;
+
+jit_failure:
+ zend_arena_release(&CG(arena), checkpoint);
+ return FAILURE;
+}
+
+/* Run-time JIT handler */
+static void ZEND_FASTCALL zend_runtime_jit(void)
+{
+ zend_execute_data *execute_data = EG(current_execute_data);
+ zend_op_array *op_array = &EX(func)->op_array;
+ zend_op *opline = op_array->opcodes;
+
+ zend_shared_alloc_lock();
+
+ if (ZEND_FUNC_INFO(op_array)) {
+ SHM_UNPROTECT();
+ zend_jit_unprotect();
+
+ /* restore original opcode handlers */
+ if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
+ while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
+ opline++;
+ }
+ }
+ opline->handler = ZEND_FUNC_INFO(op_array);
+ ZEND_SET_FUNC_INFO(op_array, NULL);
+
+ /* perform real JIT for this function */
+ zend_real_jit_func(op_array, NULL, NULL);
+
+ zend_jit_protect();
+ SHM_PROTECT();
+ }
+
+ zend_shared_alloc_unlock();
+
+ /* JIT-ed code is going to be called by VM */
+}
+
+void zend_jit_check_funcs(HashTable *function_table, zend_bool is_method) {
+ zend_op *opline;
+ zend_function *func;
+ zend_op_array *op_array;
+ uintptr_t counter;
+
+ ZEND_HASH_REVERSE_FOREACH_PTR(function_table, func) {
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
+ break;
+ }
+ op_array = &func->op_array;
+ opline = op_array->opcodes;
+ if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
+ while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
+ opline++;
+ }
+ }
+ if (opline->handler == zend_jit_profile_jit_handler) {
+ if (!RUN_TIME_CACHE(op_array)) {
+ continue;
+ }
+ counter = (uintptr_t)ZEND_COUNTER_INFO(op_array);
+ ZEND_COUNTER_INFO(op_array) = 0;
+ opline->handler = ZEND_FUNC_INFO(op_array);
+ ZEND_SET_FUNC_INFO(op_array, NULL);
+ if (((double)counter / (double)zend_jit_profile_counter) > ZEND_JIT_PROF_THRESHOLD) {
+ zend_real_jit_func(op_array, NULL, NULL);
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+}
+
+void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline)
+{
+ zend_op_array *op_array = &EX(func)->op_array;
+ zend_jit_op_array_extension *jit_extension;
+ uint32_t i;
+
+ zend_shared_alloc_lock();
+ jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
+
+ if (jit_extension) {
+ SHM_UNPROTECT();
+ zend_jit_unprotect();
+
+ *(jit_extension->counter) = ZEND_JIT_HOT_COUNTER_INIT;
+ for (i = 0; i < op_array->last; i++) {
+ op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
+ }
+ ZEND_SET_FUNC_INFO(op_array, NULL);
+
+ /* perform real JIT for this function */
+ zend_real_jit_func(op_array, NULL, opline);
+
+ zend_jit_protect();
+ SHM_PROTECT();
+ }
+
+ zend_shared_alloc_unlock();
+
+ /* JIT-ed code is going to be called by VM */
+}
+
+static int zend_jit_setup_hot_counters(zend_op_array *op_array)
+{
+ zend_op *opline = op_array->opcodes;
+ zend_jit_op_array_extension *jit_extension;
+ zend_cfg cfg;
+ uint32_t i;
+
+ ZEND_ASSERT(zend_jit_func_counter_handler != NULL);
+ ZEND_ASSERT(zend_jit_loop_counter_handler != NULL);
+
+ if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
+ return FAILURE;
+ }
+
+ jit_extension = (zend_jit_op_array_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_extension) + (op_array->last - 1) * sizeof(void*));
+ jit_extension->counter = &zend_jit_hot_counters[zend_jit_op_array_hash(op_array) & (ZEND_HOT_COUNTERS_COUNT - 1)];
+ for (i = 0; i < op_array->last; i++) {
+ jit_extension->orig_handlers[i] = op_array->opcodes[i].handler;
+ }
+ ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
+
+ if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
+ while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
+ opline++;
+ }
+ }
+
+ opline->handler = (const void*)zend_jit_func_counter_handler;
+
+ for (i = 0; i < cfg.blocks_count; i++) {
+ if ((cfg.blocks[i].flags & ZEND_BB_REACHABLE) &&
+ (cfg.blocks[i].flags & ZEND_BB_LOOP_HEADER)) {
+ op_array->opcodes[cfg.blocks[i].start].handler =
+ (const void*)zend_jit_loop_counter_handler;
+ }
+ }
+
+ return SUCCESS;
+}
+
+static int zend_needs_manual_jit(const zend_op_array *op_array)
+{
+ if (op_array->doc_comment) {
+ const char *s = ZSTR_VAL(op_array->doc_comment);
+ const char *p = strstr(s, "@jit");
+
+ if (p) {
+ size_t l = ZSTR_LEN(op_array->doc_comment);
+
+ if ((p == s + 3 || *(p-1) <= ' ') &&
+ (p + 6 == s + l || *(p+4) <= ' ')) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+ZEND_EXT_API int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
+{
+ if (dasm_ptr == NULL) {
+ return FAILURE;
+ }
+
+ if (zend_jit_trigger == ZEND_JIT_ON_FIRST_EXEC) {
+ zend_op *opline = op_array->opcodes;
+
+ /* Set run-time JIT handler */
+ ZEND_ASSERT(zend_jit_runtime_jit_handler != NULL);
+ if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
+ while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
+ opline++;
+ }
+ }
+ ZEND_SET_FUNC_INFO(op_array, (void*)opline->handler);
+ opline->handler = (const void*)zend_jit_runtime_jit_handler;
+
+ return SUCCESS;
+ } else if (zend_jit_trigger == ZEND_JIT_ON_PROF_REQUEST) {
+ zend_op *opline = op_array->opcodes;
+
+ ZEND_ASSERT(zend_jit_profile_jit_handler != NULL);
+ if (op_array->function_name) {
+ if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
+ while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
+ opline++;
+ }
+ }
+ ZEND_SET_FUNC_INFO(op_array, (void*)opline->handler);
+ opline->handler = (const void*)zend_jit_profile_jit_handler;
+ }
+
+ return SUCCESS;
+ } else if (zend_jit_trigger == ZEND_JIT_ON_HOT_COUNTERS) {
+ return zend_jit_setup_hot_counters(op_array);
+ } else if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD) {
+ return zend_real_jit_func(op_array, script, NULL);
+ } else if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT) {
+ if (zend_needs_manual_jit(op_array)) {
+ return zend_real_jit_func(op_array, script, NULL);
+ } else {
+ return SUCCESS;
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+}
+
+ZEND_EXT_API int zend_jit_script(zend_script *script)
+{
+ void *checkpoint;
+ zend_call_graph call_graph;
+ zend_func_info *info;
+ int i;
+
+ if (dasm_ptr == NULL || *dasm_ptr == dasm_end) {
+ return FAILURE;
+ }
+
+ checkpoint = zend_arena_checkpoint(CG(arena));
+
+ call_graph.op_arrays_count = 0;
+ if (zend_build_call_graph(&CG(arena), script, &call_graph) != SUCCESS) {
+ goto jit_failure;
+ }
+
+ zend_analyze_call_graph(&CG(arena), script, &call_graph);
+
+ if (zend_jit_trigger == ZEND_JIT_ON_FIRST_EXEC ||
+ zend_jit_trigger == ZEND_JIT_ON_PROF_REQUEST ||
+ zend_jit_trigger == ZEND_JIT_ON_HOT_COUNTERS) {
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
+ if (zend_jit_op_array(call_graph.op_arrays[i], script) != SUCCESS) {
+ goto jit_failure;
+ }
+ }
+ } else if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD ||
+ zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT) {
+
+ if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT) {
+ int do_jit = 0;
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ if (zend_needs_manual_jit(call_graph.op_arrays[i])) {
+ do_jit = 1;
+ break;
+ }
+ }
+ if (!do_jit) {
+ goto jit_failure;
+ }
+ }
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+ if (info) {
+ if (zend_jit_op_array_analyze1(call_graph.op_arrays[i], script, &info->ssa) != SUCCESS) {
+ goto jit_failure;
+ }
+ info->flags = info->ssa.cfg.flags;
+ }
+ }
+
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+ if (info) {
+ info->call_map = zend_build_call_map(&CG(arena), info, call_graph.op_arrays[i]);
+ if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ zend_init_func_return_info(call_graph.op_arrays[i], script, &info->return_info);
+ }
+ }
+ }
+
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT &&
+ !zend_needs_manual_jit(call_graph.op_arrays[i])) {
+ continue;
+ }
+ info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+ if (info) {
+ if (zend_jit_op_array_analyze2(call_graph.op_arrays[i], script, &info->ssa) != SUCCESS) {
+ goto jit_failure;
+ }
+ info->flags = info->ssa.cfg.flags;
+ }
+ }
+
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_SSA) {
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT &&
+ !zend_needs_manual_jit(call_graph.op_arrays[i])) {
+ continue;
+ }
+ info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+ if (info) {
+ zend_dump_op_array(call_graph.op_arrays[i], ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &info->ssa);
+ }
+ }
+ }
+
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT &&
+ !zend_needs_manual_jit(call_graph.op_arrays[i])) {
+ continue;
+ }
+ info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
+ if (info) {
+ if (zend_jit(call_graph.op_arrays[i], &info->ssa, NULL) != SUCCESS) {
+ goto jit_failure;
+ }
+ }
+ }
+
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+ zend_arena_release(&CG(arena), checkpoint);
+ return SUCCESS;
+
+jit_failure:
+ for (i = 0; i < call_graph.op_arrays_count; i++) {
+ ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
+ }
+ zend_arena_release(&CG(arena), checkpoint);
+ return FAILURE;
+}
+
+ZEND_EXT_API void zend_jit_unprotect(void)
+{
+#ifdef HAVE_MPROTECT
+ if (!(ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
+ if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE) != 0) {
+ fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
+ }
+ }
+#elif _WIN32
+ if (!(ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
+ DWORD old;
+
+ if (!VirtualProtect(dasm_buf, dasm_size, PAGE_READWRITE, &old)) {
+ fprintf(stderr, "VirtualProtect() failed\n");
+ }
+ }
+#endif
+}
+
+ZEND_EXT_API void zend_jit_protect(void)
+{
+#ifdef HAVE_MPROTECT
+ if (!(ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
+ if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
+ fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
+ }
+ }
+#elif _WIN32
+ if (!(ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
+ DWORD old;
+
+ if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
+ fprintf(stderr, "VirtualProtect() failed\n");
+ }
+ }
+#endif
+}
+
+static int zend_jit_make_stubs(void)
+{
+ dasm_State* dasm_state = NULL;
+ uint32_t i;
+
+ dasm_init(&dasm_state, DASM_MAXSECTION);
+ dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX);
+
+ for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
+ dasm_setup(&dasm_state, dasm_actions);
+ if (!zend_jit_stubs[i].stub(&dasm_state)) {
+ return 0;
+ }
+ if (!dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, zend_jit_stubs[i].name)) {
+ return 0;
+ }
+ }
+
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ if (zend_jit_trigger == ZEND_JIT_ON_FIRST_EXEC) {
+ dasm_setup(&dasm_state, dasm_actions);
+ if (!zend_jit_hybrid_runtime_jit_stub(&dasm_state)) {
+ return 0;
+ }
+ zend_jit_runtime_jit_handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, "JIT$$hybrid_runtime_jit");
+ if (!zend_jit_runtime_jit_handler) {
+ return 0;
+ }
+ } else if (zend_jit_trigger == ZEND_JIT_ON_PROF_REQUEST) {
+ dasm_setup(&dasm_state, dasm_actions);
+ if (!zend_jit_hybrid_profile_jit_stub(&dasm_state)) {
+ return 0;
+ }
+ zend_jit_profile_jit_handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, "JIT$$hybrid_profile_jit");
+ if (!zend_jit_profile_jit_handler) {
+ return 0;
+ }
+ } else if (zend_jit_trigger == ZEND_JIT_ON_HOT_COUNTERS) {
+ dasm_setup(&dasm_state, dasm_actions);
+ if (!zend_jit_hybrid_func_counter_stub(&dasm_state)) {
+ return 0;
+ }
+ zend_jit_func_counter_handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, "JIT$$hybrid_func_counter");
+ if (!zend_jit_func_counter_handler) {
+ return 0;
+ }
+
+ dasm_setup(&dasm_state, dasm_actions);
+ if (!zend_jit_hybrid_loop_counter_stub(&dasm_state)) {
+ return 0;
+ }
+ zend_jit_loop_counter_handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, "JIT$$hybrid_loop_counter");
+ if (!zend_jit_loop_counter_handler) {
+ return 0;
+ }
+ }
+ } else {
+ zend_jit_runtime_jit_handler = (const void*)zend_runtime_jit;
+ zend_jit_profile_jit_handler = (const void*)zend_jit_profile_helper;
+ zend_jit_func_counter_handler = (const void*)zend_jit_func_counter_helper;
+ zend_jit_loop_counter_handler = (const void*)zend_jit_loop_counter_helper;
+ }
+
+ dasm_free(&dasm_state);
+ return 1;
+}
+
+ZEND_EXT_API int zend_jit_startup(zend_long jit, void *buf, size_t size, zend_bool reattached)
+{
+ int ret;
+
+ zend_jit_level = ZEND_JIT_LEVEL(jit);
+ zend_jit_trigger = ZEND_JIT_TRIGGER(jit);
+ zend_jit_reg_alloc = ZEND_JIT_REG_ALLOC(jit);
+ zend_jit_cpu_flags = ZEND_JIT_CPU_FLAGS(jit);
+
+ zend_jit_vm_kind = zend_vm_kind();
+ if (zend_jit_vm_kind != ZEND_VM_KIND_CALL &&
+ zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
+ // TODO: error reporting and cleanup ???
+ return FAILURE;
+ }
+
+ zend_jit_halt_op = zend_get_halt_op();
+
+ if (zend_jit_setup() != SUCCESS) {
+ // TODO: error reporting and cleanup ???
+ return FAILURE;
+ }
+
+ if (zend_jit_trigger == ZEND_JIT_ON_PROF_REQUEST) {
+ zend_jit_profile_counter_rid = zend_get_op_array_extension_handle();
+ }
+
+#ifdef HAVE_GDB
+ zend_jit_gdb_init();
+#endif
+
+#ifdef HAVE_OPROFILE
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_OPROFILE) {
+ if (!zend_jit_oprofile_startup()) {
+ // TODO: error reporting and cleanup ???
+ return FAILURE;
+ }
+ }
+#endif
+
+ dasm_buf = buf;
+ dasm_size = size;
+
+#ifdef HAVE_MPROTECT
+ if (ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
+ if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
+ fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
+ }
+ } else {
+ if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
+ fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
+ }
+ }
+#elif _WIN32
+ if (ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
+ DWORD old;
+
+ if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READWRITE, &old)) {
+ fprintf(stderr, "VirtualProtect() failed\n");
+ }
+ } else {
+ DWORD old;
+
+ if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
+ fprintf(stderr, "VirtualProtect() failed\n");
+ }
+ }
+#endif
+
+ dasm_ptr = dasm_end = (void*)(((char*)dasm_buf) + size - sizeof(*dasm_ptr));
+ if (!reattached) {
+ zend_jit_unprotect();
+ *dasm_ptr = dasm_buf;
+#if _WIN32
+ /* reserve space for global labels */
+ *dasm_ptr = (void**)*dasm_ptr + zend_lb_MAX;
+#endif
+ zend_jit_protect();
+ }
+
+#ifdef HAVE_DISASM
+ if (ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
+ if (!zend_jit_disasm_init()) {
+ // TODO: error reporting and cleanup ???
+ return FAILURE;
+ }
+ }
+#endif
+
+#ifdef HAVE_PERFTOOLS
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_PERF_DUMP) {
+ zend_jit_perf_jitdump_open();
+ }
+#endif
+
+ if (!reattached) {
+ zend_jit_unprotect();
+ ret = zend_jit_make_stubs();
+#if _WIN32
+ /* save global labels */
+ memcpy(dasm_buf, dasm_labels, sizeof(void*) * zend_lb_MAX);
+#endif
+ zend_jit_protect();
+ if (!ret) {
+ // TODO: error reporting and cleanup ???
+ return FAILURE;
+ }
+ } else {
+#if _WIN32
+ /* restore global labels */
+ memcpy(dasm_labels, dasm_buf, sizeof(void*) * zend_lb_MAX);
+#endif
+ }
+
+ return SUCCESS;
+}
+
+ZEND_EXT_API void zend_jit_shutdown(void)
+{
+#ifdef HAVE_OPROFILE
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_OPROFILE) {
+ zend_jit_oprofile_shutdown();
+ }
+#endif
+
+#ifdef HAVE_GDB
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_GDB) {
+ zend_jit_gdb_unregister();
+ }
+#endif
+
+#ifdef HAVE_DISASM
+ if (ZCG(accel_directives).jit_debug & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
+ zend_jit_disasm_shutdown();
+ }
+#endif
+
+#ifdef HAVE_PERFTOOLS
+ if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_PERF_DUMP) {
+ zend_jit_perf_jitdump_close();
+ }
+#endif
+}
+
+ZEND_EXT_API void zend_jit_activate(void)
+{
+ if (zend_jit_trigger == ZEND_JIT_ON_HOT_COUNTERS) {
+ int i;
+
+ for (i = 0; i < ZEND_HOT_COUNTERS_COUNT; i++) {
+ zend_jit_hot_counters[i] = ZEND_JIT_HOT_COUNTER_INIT;
+ }
+ }
+}
+
+ZEND_EXT_API void zend_jit_deactivate(void)
+{
+ if (zend_jit_trigger == ZEND_JIT_ON_PROF_REQUEST) {
+ if (!zend_jit_profile_counter) {
+ return;
+ } else {
+ zend_class_entry *ce;
+
+ zend_shared_alloc_lock();
+ SHM_UNPROTECT();
+ zend_jit_unprotect();
+
+ zend_jit_check_funcs(EG(function_table), 0);
+ ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ break;
+ }
+ zend_jit_check_funcs(&ce->function_table, 1);
+ } ZEND_HASH_FOREACH_END();
+
+ zend_jit_protect();
+ SHM_PROTECT();
+ zend_shared_alloc_unlock();
+
+ zend_jit_profile_counter = 0;
+ }
+ }
+}
+
+#else /* HAVE_JIT */
+
+ZEND_EXT_API int zend_jit_op_array(const zend_op_array *op_array, zend_script *script)
+{
+ return FAILURE;
+}
+
+ZEND_EXT_API int zend_jit_script(zend_script *script)
+{
+ return FAILURE;
+}
+
+ZEND_EXT_API void zend_jit_unprotect(void)
+{
+}
+
+ZEND_EXT_API void zend_jit_protect(void)
+{
+}
+
+ZEND_EXT_API int zend_jit_startup(zend_long jit, size_t size)
+{
+ return FAILURE;
+}
+
+ZEND_EXT_API void zend_jit_shutdown(void)
+{
+}
+
+ZEND_EXT_API void zend_jit_activate(void)
+{
+}
+
+ZEND_EXT_API void zend_jit_deactivate(void)
+{
+}
+
+#endif /* HAVE_JIT */
diff --git a/ext/opcache/jit/zend_jit.h b/ext/opcache/jit/zend_jit.h
new file mode 100644
index 0000000000..5234660398
--- /dev/null
+++ b/ext/opcache/jit/zend_jit.h
@@ -0,0 +1,109 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef HAVE_JIT_H
+#define HAVE_JIT_H
+
+#define ZEND_JIT_LEVEL_NONE 0 /* no JIT */
+#define ZEND_JIT_LEVEL_MINIMAL 1 /* minimal JIT (subroutine threading) */
+#define ZEND_JIT_LEVEL_INLINE 2 /* selective inline threading */
+#define ZEND_JIT_LEVEL_OPT_FUNC 3 /* optimized JIT based on Type-Inference */
+#define ZEND_JIT_LEVEL_OPT_FUNCS 4 /* optimized JIT based on Type-Inference and call-tree */
+#define ZEND_JIT_LEVEL_OPT_SCRIPT 5 /* optimized JIT based on Type-Inference and inner-procedure analysis */
+
+#define ZEND_JIT_LEVEL(n) ((n) % 10)
+
+#define ZEND_JIT_ON_SCRIPT_LOAD 0
+#define ZEND_JIT_ON_FIRST_EXEC 1
+#define ZEND_JIT_ON_PROF_REQUEST 2 /* compile the most frequently caled on first request functions */
+#define ZEND_JIT_ON_HOT_COUNTERS 3 /* compile functions after N calls or loop iterations */
+#define ZEND_JIT_ON_DOC_COMMENT 4 /* compile functions with "@jit" tag in doc-comments */
+
+#define ZEND_JIT_TRIGGER(n) (((n) / 10) % 10)
+
+#define ZEND_JIT_REG_ALLOC_NONE 0 /* no register allocation */
+#define ZEND_JIT_REG_ALLOC_ENABLED 1 /* local linear scan register allocation */
+#define ZEND_JIT_REG_ALLOC_GLOBAL 2 /* global linear scan register allocation */
+
+#define ZEND_JIT_REG_ALLOC(n) (((n) / 100) % 10)
+
+#define ZEND_JIT_CPU_AVX 1 /* use AVX instructions, if available */
+
+#define ZEND_JIT_CPU_FLAGS(n) (((n) / 1000) % 10)
+
+
+#define ZEND_JIT_DEFAULT "1205"
+
+
+/* Makes profile based JIT (opcache.jit=2*) to generate code only for most
+ * often called functions (above the threshold).
+ * TODO: this setting should be configurable
+ */
+#define ZEND_JIT_PROF_THRESHOLD 0.005
+
+/* Hot Counters based JIT parameters.
+ * TODO: this setting should be configurable
+ */
+#define ZEND_JIT_HOT_FUNC_COST 1
+#define ZEND_JIT_HOT_LOOP_COST 2
+#define ZEND_JIT_HOT_COUNTER_INIT 127
+
+#define ZEND_JIT_DEBUG_ASM (1<<0)
+#define ZEND_JIT_DEBUG_SSA (1<<1)
+#define ZEND_JIT_DEBUG_REG_ALLOC (1<<2)
+#define ZEND_JIT_DEBUG_ASM_STUBS (1<<3)
+
+#define ZEND_JIT_DEBUG_PERF (1<<4)
+#define ZEND_JIT_DEBUG_PERF_DUMP (1<<5)
+#define ZEND_JIT_DEBUG_OPROFILE (1<<6)
+#define ZEND_JIT_DEBUG_VTUNE (1<<7)
+
+#define ZEND_JIT_DEBUG_GDB (1<<8)
+
+ZEND_EXT_API int zend_jit_op_array(zend_op_array *op_array, zend_script *script);
+ZEND_EXT_API int zend_jit_script(zend_script *script);
+ZEND_EXT_API void zend_jit_unprotect(void);
+ZEND_EXT_API void zend_jit_protect(void);
+ZEND_EXT_API int zend_jit_startup(zend_long jit, void *jit_buffer, size_t size, zend_bool reattached);
+ZEND_EXT_API void zend_jit_shutdown(void);
+ZEND_EXT_API void zend_jit_activate(void);
+ZEND_EXT_API void zend_jit_deactivate(void);
+ZEND_EXT_API void zend_jit_status(zval *ret);
+
+typedef struct _zend_lifetime_interval zend_lifetime_interval;
+typedef struct _zend_life_range zend_life_range;
+
+struct _zend_life_range {
+ uint32_t start;
+ uint32_t end;
+ zend_life_range *next;
+};
+
+struct _zend_lifetime_interval {
+ int ssa_var;
+ int8_t reg;
+ zend_bool split;
+ zend_bool store;
+ zend_bool load;
+ zend_life_range range;
+ zend_lifetime_interval *hint;
+ zend_lifetime_interval *used_as_hint;
+ zend_lifetime_interval *list_next;
+};
+
+#endif /* HAVE_JIT_H */
diff --git a/ext/opcache/jit/zend_jit_disasm_x86.c b/ext/opcache/jit/zend_jit_disasm_x86.c
new file mode 100644
index 0000000000..4ee7f2277c
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_disasm_x86.c
@@ -0,0 +1,519 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ | Xinchen Hui <laruence@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#define HAVE_DISASM 1
+#define DISASM_INTEL_SYNTAX 0
+
+#include "jit/libudis86/itab.c"
+#include "jit/libudis86/decode.c"
+#include "jit/libudis86/syn.c"
+#if DISASM_INTEL_SYNTAX
+# include "jit/libudis86/syn-intel.c"
+#else
+# include "jit/libudis86/syn-att.c"
+#endif
+#include "jit/libudis86/udis86.c"
+
+static void zend_jit_disasm_add_symbol(const char *name,
+ uint64_t addr,
+ uint64_t size);
+
+#ifndef _WIN32
+# include "jit/zend_elf.c"
+#endif
+
+#include "zend_sort.h"
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
+
+static struct ud ud;
+
+typedef struct _sym_node {
+ uint64_t addr;
+ uint64_t end;
+ struct _sym_node *parent;
+ struct _sym_node *child[2];
+ unsigned char info;
+ char name[1];
+} zend_sym_node;
+
+static zend_sym_node *symbols = NULL;
+
+static void zend_syms_rotateleft(zend_sym_node *p) {
+ zend_sym_node *r = p->child[1];
+ p->child[1] = r->child[0];
+ if (r->child[0]) {
+ r->child[0]->parent = p;
+ }
+ r->parent = p->parent;
+ if (p->parent == NULL) {
+ symbols = r;
+ } else if (p->parent->child[0] == p) {
+ p->parent->child[0] = r;
+ } else {
+ p->parent->child[1] = r;
+ }
+ r->child[0] = p;
+ p->parent = r;
+}
+
+static void zend_syms_rotateright(zend_sym_node *p) {
+ zend_sym_node *l = p->child[0];
+ p->child[0] = l->child[1];
+ if (l->child[1]) {
+ l->child[1]->parent = p;
+ }
+ l->parent = p->parent;
+ if (p->parent == NULL) {
+ symbols = l;
+ } else if (p->parent->child[1] == p) {
+ p->parent->child[1] = l;
+ } else {
+ p->parent->child[0] = l;
+ }
+ l->child[1] = p;
+ p->parent = l;
+}
+
+static void zend_jit_disasm_add_symbol(const char *name,
+ uint64_t addr,
+ uint64_t size)
+{
+ zend_sym_node *sym;
+ size_t len = strlen(name);
+
+ sym = malloc(sizeof(zend_sym_node) + len + 1);
+ if (!sym) {
+ return;
+ }
+ sym->addr = addr;
+ sym->end = (addr + size - 1);
+ memcpy((char*)&sym->name, name, len + 1);
+ sym->parent = sym->child[0] = sym->child[1] = NULL;
+ sym->info = 1;
+ if (symbols) {
+ zend_sym_node *node = symbols;
+
+ /* insert it into rbtree */
+ do {
+ if (sym->addr > node->addr) {
+ ZEND_ASSERT(sym->addr > (node->end));
+ if (node->child[1]) {
+ node = node->child[1];
+ } else {
+ node->child[1] = sym;
+ sym->parent = node;
+ break;
+ }
+ } else if (sym->addr < node->addr) {
+ if (node->child[0]) {
+ node = node->child[0];
+ } else {
+ node->child[0] = sym;
+ sym->parent = node;
+ break;
+ }
+ } else {
+ ZEND_ASSERT(sym->addr == node->addr);
+ free(sym);
+ return;
+ }
+ } while (1);
+
+ /* fix rbtree after instering */
+ while (sym && sym != symbols && sym->parent->info == 1) {
+ if (sym->parent == sym->parent->parent->child[0]) {
+ node = sym->parent->parent->child[1];
+ if (node && node->info == 1) {
+ sym->parent->info = 0;
+ node->info = 0;
+ sym->parent->parent->info = 1;
+ sym = sym->parent->parent;
+ } else {
+ if (sym == sym->parent->child[1]) {
+ sym = sym->parent;
+ zend_syms_rotateleft(sym);
+ }
+ sym->parent->info = 0;
+ sym->parent->parent->info = 1;
+ zend_syms_rotateright(sym->parent->parent);
+ }
+ } else {
+ node = sym->parent->parent->child[0];
+ if (node && node->info == 1) {
+ sym->parent->info = 0;
+ node->info = 0;
+ sym->parent->parent->info = 1;
+ sym = sym->parent->parent;
+ } else {
+ if (sym == sym->parent->child[0]) {
+ sym = sym->parent;
+ zend_syms_rotateright(sym);
+ }
+ sym->parent->info = 0;
+ sym->parent->parent->info = 1;
+ zend_syms_rotateleft(sym->parent->parent);
+ }
+ }
+ }
+ } else {
+ symbols = sym;
+ }
+ symbols->info = 0;
+}
+
+static void zend_jit_disasm_destroy_symbols(zend_sym_node *n) {
+ if (n) {
+ if (n->child[0]) {
+ zend_jit_disasm_destroy_symbols(n->child[0]);
+ } else if (n->child[1]) {
+ zend_jit_disasm_destroy_symbols(n->child[1]);
+ }
+ free(n);
+ }
+}
+
+static const char* zend_jit_disasm_find_symbol(uint64_t addr,
+ int64_t *offset) {
+ zend_sym_node *node = symbols;
+ while (node) {
+ if (addr < node->addr) {
+ node = node->child[0];
+ } else if (addr > node->end) {
+ node = node->child[1];
+ } else {
+ *offset = addr - node->addr;
+ return node->name;
+ }
+ }
+ return NULL;
+}
+
+static const char* zend_jit_disasm_resolver(struct ud *ud,
+ uint64_t addr,
+ int64_t *offset)
+{
+#ifndef _WIN32
+ ((void)ud);
+ const char *name;
+ void *a = (void*)(zend_uintptr_t)(addr);
+ Dl_info info;
+
+ name = zend_jit_disasm_find_symbol(addr, offset);
+ if (name) {
+ return name;
+ }
+
+ if (dladdr(a, &info)
+ && info.dli_sname != NULL
+ && info.dli_saddr == a) {
+ return info.dli_sname;
+ }
+#else
+ const char *name;
+ name = zend_jit_disasm_find_symbol(addr, offset);
+ if (name) {
+ return name;
+ }
+#endif
+
+ return NULL;
+}
+
+static int zend_jit_cmp_labels(Bucket *b1, Bucket *b2)
+{
+ return ((b1->h > b2->h) > 0) ? 1 : -1;
+}
+
+static int zend_jit_disasm(const char *name,
+ const char *filename,
+ const zend_op_array *op_array,
+ zend_cfg *cfg,
+ const void *start,
+ size_t size)
+{
+ const void *end = (void *)((char *)start + size);
+ zval zv, *z;
+ zend_long n, m;
+ HashTable labels;
+ const struct ud_operand *op;
+ uint64_t addr;
+ int b;
+
+ if (name) {
+ fprintf(stderr, "%s: ; (%s)\n", name, filename ? filename : "unknown");
+ }
+
+ ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
+ ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
+
+ zend_hash_init(&labels, 8, NULL, NULL, 0);
+ if (op_array && cfg) {
+ ZVAL_FALSE(&zv);
+ for (b = 0; b < cfg->blocks_count; b++) {
+ if (cfg->blocks[b].flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
+ addr = (uint64_t)(uintptr_t)op_array->opcodes[cfg->blocks[b].start].handler;
+ if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
+ zend_hash_index_add(&labels, addr, &zv);
+ }
+ }
+ }
+ }
+ ZVAL_TRUE(&zv);
+ while (ud_disassemble(&ud)) {
+ op = ud_insn_opr(&ud, 0);
+ if (op && op->type == UD_OP_JIMM) {
+ addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
+ if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
+ zend_hash_index_add(&labels, addr, &zv);
+ }
+ }
+ }
+
+ zend_hash_sort(&labels, (compare_func_t)zend_jit_cmp_labels, 0);
+
+ /* label numbering */
+ n = 0; m = 0;
+ ZEND_HASH_FOREACH_VAL(&labels, z) {
+ if (Z_TYPE_P(z) == IS_FALSE) {
+ m--;
+ ZVAL_LONG(z, m);
+ } else {
+ n++;
+ ZVAL_LONG(z, n);
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start);
+ ud_set_pc(&ud, (uint64_t)(uintptr_t)start);
+
+ while (ud_disassemble(&ud)) {
+ addr = ud_insn_off(&ud);
+ z = zend_hash_index_find(&labels, addr);
+ if (z) {
+ if (Z_LVAL_P(z) < 0) {
+ fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z));
+ } else {
+ fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z));
+ }
+ }
+ op = ud_insn_opr(&ud, 0);
+ if (op && op->type == UD_OP_JIMM) {
+ addr = ud_syn_rel_target(&ud, (struct ud_operand*)op);
+ if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) {
+ z = zend_hash_index_find(&labels, addr);
+ if (z) {
+ const char *str = ud_insn_asm(&ud);
+ int len;
+
+ len = 0;
+ while (str[len] != 0 && str[len] != ' ' && str[len] != '\t') {
+ len++;
+ }
+ if (str[len] != 0) {
+ while (str[len] == ' ' || str[len] == '\t') {
+ len++;
+ }
+ if (Z_LVAL_P(z) < 0) {
+ fprintf(stderr, "\t%.*s.ENTRY" ZEND_LONG_FMT "\n", len, str, -Z_LVAL_P(z));
+ } else {
+ fprintf(stderr, "\t%.*s.L" ZEND_LONG_FMT "\n", len, str, Z_LVAL_P(z));
+ }
+ continue;
+ }
+ }
+ }
+ }
+ fprintf(stderr, "\t%s\n", ud_insn_asm(&ud));
+ }
+ fprintf(stderr, "\n");
+
+ zend_hash_destroy(&labels);
+
+ return 1;
+}
+
+static int zend_jit_disasm_init(void)
+{
+ ud_init(&ud);
+#if defined(__x86_64__) || defined(_WIN64)
+ ud_set_mode(&ud, 64);
+#else
+ ud_set_mode(&ud, 32);
+#endif
+#if DISASM_INTEL_SYNTAX
+ ud_set_syntax(&ud, UD_SYN_INTEL);
+#else
+ ud_set_syntax(&ud, UD_SYN_ATT);
+#endif
+ ud_set_sym_resolver(&ud, zend_jit_disasm_resolver);
+
+#ifndef ZTS
+#define REGISTER_EG(n) \
+ zend_jit_disasm_add_symbol("EG("#n")", \
+ (uint64_t)(uintptr_t)&executor_globals.n, sizeof(executor_globals.n))
+ REGISTER_EG(uninitialized_zval);
+ REGISTER_EG(exception);
+ REGISTER_EG(vm_interrupt);
+ REGISTER_EG(exception_op);
+ REGISTER_EG(timed_out);
+ REGISTER_EG(current_execute_data);
+ REGISTER_EG(vm_stack_top);
+ REGISTER_EG(vm_stack_end);
+ REGISTER_EG(symbol_table);
+#undef REGISTER_EG
+#endif
+
+ /* Register JIT helper functions */
+#define REGISTER_HELPER(n) \
+ zend_jit_disasm_add_symbol(#n, \
+ (uint64_t)(uintptr_t)n, sizeof(void*));
+ REGISTER_HELPER(memcmp);
+ REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
+ REGISTER_HELPER(zend_jit_find_func_helper);
+ REGISTER_HELPER(zend_jit_extend_stack_helper);
+ REGISTER_HELPER(zend_jit_int_extend_stack_helper);
+ REGISTER_HELPER(zend_jit_leave_nested_func_helper);
+ REGISTER_HELPER(zend_jit_leave_top_func_helper);
+ REGISTER_HELPER(zend_jit_symtable_find);
+ REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
+ REGISTER_HELPER(zend_jit_hash_index_lookup_w);
+ REGISTER_HELPER(zend_jit_hash_lookup_rw);
+ REGISTER_HELPER(zend_jit_hash_lookup_w);
+ REGISTER_HELPER(zend_jit_symtable_lookup_rw);
+ REGISTER_HELPER(zend_jit_symtable_lookup_w);
+ REGISTER_HELPER(zend_jit_fetch_dimension_rw_long_helper);
+ REGISTER_HELPER(zend_jit_undefined_op_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
+ REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
+ REGISTER_HELPER(zend_jit_assign_dim_helper);
+ REGISTER_HELPER(zend_jit_assign_dim_op_helper);
+ REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
+ REGISTER_HELPER(zend_jit_fast_concat_helper);
+ REGISTER_HELPER(zend_jit_isset_dim_helper);
+ REGISTER_HELPER(zend_jit_free_call_frame);
+ REGISTER_HELPER(zend_jit_zval_copy_deref_helper)
+ REGISTER_HELPER(zend_jit_new_ref_helper);
+ REGISTER_HELPER(zend_jit_fetch_global_helper);
+ REGISTER_HELPER(zend_jit_verify_arg_slow);
+ REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
+ REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
+ REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
+ REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
+ REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
+ REGISTER_HELPER(zend_jit_copy_extra_args_helper);
+ REGISTER_HELPER(zend_jit_deprecated_helper);
+ REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
+ REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
+ REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
+ REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
+ REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
+ REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
+ REGISTER_HELPER(zend_jit_post_inc_typed_ref);
+ REGISTER_HELPER(zend_jit_post_dec_typed_ref);
+ REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
+ REGISTER_HELPER(zend_jit_only_vars_by_reference);
+ REGISTER_HELPER(zend_jit_invalid_array_access);
+ REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
+ REGISTER_HELPER(zend_jit_pre_inc);
+ REGISTER_HELPER(zend_jit_pre_dec);
+ REGISTER_HELPER(zend_runtime_jit);
+ REGISTER_HELPER(zend_jit_hot_func);
+#undef REGISTER_HELPER
+
+#ifndef _WIN32
+ zend_elf_load_symbols();
+#endif
+
+ if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
+ zend_op opline;
+
+ memset(&opline, 0, sizeof(opline));
+
+ opline.opcode = ZEND_DO_UCALL;
+ opline.result_type = IS_UNUSED;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_DO_UCALL;
+ opline.result_type = IS_VAR;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_DO_FCALL_BY_NAME;
+ opline.result_type = IS_UNUSED;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_DO_FCALL_BY_NAME;
+ opline.result_type = IS_VAR;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_DO_FCALL;
+ opline.result_type = IS_UNUSED;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_DO_FCALL;
+ opline.result_type = IS_VAR;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_RETURN;
+ opline.op1_type = IS_CONST;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_RETURN;
+ opline.op1_type = IS_TMP_VAR;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_RETURN;
+ opline.op1_type = IS_VAR;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+
+ opline.opcode = ZEND_RETURN;
+ opline.op1_type = IS_CV;
+ zend_vm_set_opcode_handler(&opline);
+ zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
+ }
+
+ return 1;
+}
+
+static void zend_jit_disasm_shutdown(void)
+{
+ zend_jit_disasm_destroy_symbols(symbols);
+}
diff --git a/ext/opcache/jit/zend_jit_gdb.c b/ext/opcache/jit/zend_jit_gdb.c
new file mode 100644
index 0000000000..58b075ea8c
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_gdb.c
@@ -0,0 +1,493 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ | Xinchen Hui <laruence@php.net> |
+ +----------------------------------------------------------------------+
+ | Based on Mike Pall's implementation of GDB interface for LuaJIT. |
+ | LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/ |
+ +----------------------------------------------------------------------+
+*/
+
+#define HAVE_GDB
+
+#ifdef HAVE_GDB
+
+#include "zend_elf.h"
+#include "zend_gdb.h"
+
+/* DWARF definitions. */
+#define DW_CIE_VERSION 1
+
+/* CFA (Canonical frame address) */
+enum {
+ DW_CFA_nop = 0x0,
+ DW_CFA_offset_extended = 0x5,
+ DW_CFA_def_cfa = 0xc,
+ DW_CFA_def_cfa_offset = 0xe,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_advance_loc = 0x40,
+ DW_CFA_offset = 0x80
+};
+
+enum {
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_textrel = 0x20
+};
+
+enum {
+ DW_TAG_compile_unit = 0x11
+};
+
+enum {
+ DW_children_no = 0,
+ DW_children_yes = 1
+};
+
+enum {
+ DW_AT_name = 0x03,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12
+};
+
+enum {
+ DW_FORM_addr = 0x01,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_string = 0x08
+};
+
+enum {
+ DW_LNS_extended_op = 0,
+ DW_LNS_copy = 1,
+ DW_LNS_advance_pc = 2,
+ DW_LNS_advance_line = 3
+};
+
+enum {
+ DW_LNE_end_sequence = 1,
+ DW_LNE_set_address = 2
+};
+
+enum {
+#if defined(__i386__)
+ DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX,
+ DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI,
+ DW_REG_RA,
+#elif defined(__x86_64__)
+ /* Yes, the order is strange, but correct. */
+ DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX,
+ DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP,
+ DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11,
+ DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15,
+ DW_REG_RA,
+ /* TODO: ARM supports? */
+#else
+#error "Unsupported target architecture"
+#endif
+};
+
+enum {
+ GDBJIT_SECT_NULL,
+ GDBJIT_SECT_text,
+ GDBJIT_SECT_eh_frame,
+ GDBJIT_SECT_shstrtab,
+ GDBJIT_SECT_strtab,
+ GDBJIT_SECT_symtab,
+ GDBJIT_SECT_debug_info,
+ GDBJIT_SECT_debug_abbrev,
+ GDBJIT_SECT_debug_line,
+ GDBJIT_SECT__MAX
+};
+
+enum {
+ GDBJIT_SYM_UNDEF,
+ GDBJIT_SYM_FILE,
+ GDBJIT_SYM_FUNC,
+ GDBJIT_SYM__MAX
+};
+
+typedef struct _zend_gdbjit_obj {
+ zend_elf_header hdr;
+ zend_elf_sectheader sect[GDBJIT_SECT__MAX];
+ zend_elf_symbol sym[GDBJIT_SYM__MAX];
+ uint8_t space[4096];
+} zend_gdbjit_obj;
+
+static const zend_elf_header zend_elfhdr_template = {
+ .emagic = { 0x7f, 'E', 'L', 'F' },
+#ifdef ELF64
+ .eclass = 2,
+#else
+ .eclass = 1,
+#endif
+#ifdef WORDS_BIGENDIAN
+ .eendian = 2,
+#else
+ .eendian = 1,
+#endif
+ .eversion = 1,
+#if defined(Linux)
+ .eosabi = 0, /* Nope, it's not 3. ??? */
+#elif defined(__FreeBSD__)
+ .eosabi = 9,
+#elif defined(__OpenBSD__)
+ .eosabi = 12,
+#elif defined(__DragonFly__)
+ .eosabi = 0,
+#elif (defined(__sun__) && defined(__svr4__))
+ .eosabi = 6,
+#else
+ .eosabi = 0,
+#endif
+ .eabiversion = 0,
+ .epad = { 0, 0, 0, 0, 0, 0, 0 },
+ .type = 1,
+#if defined(__i386__)
+ .machine = 3,
+#elif defined(__x86_64__)
+ .machine = 62,
+#else
+# error "Unsupported target architecture"
+#endif
+ .version = 1,
+ .entry = 0,
+ .phofs = 0,
+ .shofs = offsetof(zend_gdbjit_obj, sect),
+ .flags = 0,
+ .ehsize = sizeof(zend_elf_header),
+ .phentsize = 0,
+ .phnum = 0,
+ .shentsize = sizeof(zend_elf_sectheader),
+ .shnum = GDBJIT_SECT__MAX,
+ .shstridx = GDBJIT_SECT_shstrtab
+};
+
+/* Context for generating the ELF object for the GDB JIT API. */
+typedef struct _zend_gdbjit_ctx {
+ uint8_t *p; /* Pointer to next address in obj.space. */
+ uint8_t *startp; /* Pointer to start address in obj.space. */
+ uintptr_t mcaddr; /* Machine code address. */
+ uint32_t szmcode; /* Size of machine code. */
+ int32_t lineno; /* Starting line number. */
+ const char *name; /* JIT function name */
+ const char *filename; /* Starting file name. */
+ size_t objsize; /* Final size of ELF object. */
+ zend_gdbjit_obj obj; /* In-memory ELF object. */
+} zend_gdbjit_ctx;
+
+/* Add a zero-terminated string */
+static uint32_t zend_gdbjit_strz(zend_gdbjit_ctx *ctx, const char *str)
+{
+ uint8_t *p = ctx->p;
+ uint32_t ofs = (uint32_t)(p - ctx->startp);
+ do {
+ *p++ = (uint8_t)*str;
+ } while (*str++);
+ ctx->p = p;
+ return ofs;
+}
+
+/* Add a ULEB128 value */
+static void zend_gdbjit_uleb128(zend_gdbjit_ctx *ctx, uint32_t v)
+{
+ uint8_t *p = ctx->p;
+ for (; v >= 0x80; v >>= 7)
+ *p++ = (uint8_t)((v & 0x7f) | 0x80);
+ *p++ = (uint8_t)v;
+ ctx->p = p;
+}
+
+/* Add a SLEB128 value */
+static void zend_gdbjit_sleb128(zend_gdbjit_ctx *ctx, int32_t v)
+{
+ uint8_t *p = ctx->p;
+ for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7)
+ *p++ = (uint8_t)((v & 0x7f) | 0x80);
+ *p++ = (uint8_t)(v & 0x7f);
+ ctx->p = p;
+}
+
+static void zend_gdbjit_secthdr(zend_gdbjit_ctx *ctx)
+{
+ zend_elf_sectheader *sect;
+
+ *ctx->p++ = '\0';
+
+#define SECTDEF(id, tp, al) \
+ sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \
+ sect->name = zend_gdbjit_strz(ctx, "." #id); \
+ sect->type = ELFSECT_TYPE_##tp; \
+ sect->align = (al)
+
+ SECTDEF(text, NOBITS, 16);
+ sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC;
+ sect->addr = ctx->mcaddr;
+ sect->ofs = 0;
+ sect->size = ctx->szmcode;
+
+ SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t));
+ sect->flags = ELFSECT_FLAGS_ALLOC;
+
+ SECTDEF(shstrtab, STRTAB, 1);
+ SECTDEF(strtab, STRTAB, 1);
+
+ SECTDEF(symtab, SYMTAB, sizeof(uintptr_t));
+ sect->ofs = offsetof(zend_gdbjit_obj, sym);
+ sect->size = sizeof(ctx->obj.sym);
+ sect->link = GDBJIT_SECT_strtab;
+ sect->entsize = sizeof(zend_elf_symbol);
+ sect->info = GDBJIT_SYM_FUNC;
+
+ SECTDEF(debug_info, PROGBITS, 1);
+ SECTDEF(debug_abbrev, PROGBITS, 1);
+ SECTDEF(debug_line, PROGBITS, 1);
+
+#undef SECTDEF
+}
+
+static void zend_gdbjit_symtab(zend_gdbjit_ctx *ctx)
+{
+ zend_elf_symbol *sym;
+
+ *ctx->p++ = '\0';
+
+ sym = &ctx->obj.sym[GDBJIT_SYM_FILE];
+ sym->name = zend_gdbjit_strz(ctx, "JIT code");
+ sym->sectidx = ELFSECT_IDX_ABS;
+ sym->info = ELFSYM_INFO(ELFSYM_BIND_LOCAL, ELFSYM_TYPE_FILE);
+
+ sym = &ctx->obj.sym[GDBJIT_SYM_FUNC];
+ sym->name = zend_gdbjit_strz(ctx, ctx->name);
+ sym->sectidx = GDBJIT_SECT_text;
+ sym->value = 0;
+ sym->size = ctx->szmcode;
+ sym->info = ELFSYM_INFO(ELFSYM_BIND_GLOBAL, ELFSYM_TYPE_FUNC);
+}
+
+#define SECTALIGN(p, a) \
+ ((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1)))
+
+/* Shortcuts to generate DWARF structures. */
+#define DB(x) (*p++ = (x))
+#define DI8(x) (*(int8_t *)p = (x), p++)
+#define DU16(x) (*(uint16_t *)p = (x), p += 2)
+#define DU32(x) (*(uint32_t *)p = (x), p += 4)
+#define DADDR(x) (*(uintptr_t *)p = (x), p += sizeof(uintptr_t))
+#define DUV(x) (ctx->p = p, zend_gdbjit_uleb128(ctx, (x)), p = ctx->p)
+#define DSV(x) (ctx->p = p, zend_gdbjit_sleb128(ctx, (x)), p = ctx->p)
+#define DSTR(str) (ctx->p = p, zend_gdbjit_strz(ctx, (str)), p = ctx->p)
+#define DALIGNNOP(s) while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop
+#define DSECT(name, stmt) \
+ { uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \
+ *szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); }
+
+static void zend_gdbjit_ehframe(zend_gdbjit_ctx *ctx)
+{
+ uint8_t *p = ctx->p;
+ uint8_t *framep = p;
+
+ /* DWARF EH CIE (Common Information Entry) */
+ DSECT(CIE,
+ DU32(0); /* CIE ID. */
+ DB(DW_CIE_VERSION); /* Version */
+ DSTR("zR"); /* Augmentation String. */
+ DUV(1); /* Code alignment factor. */
+ DSV(-(int32_t)sizeof(uintptr_t)); /* Data alignment factor. */
+ DB(DW_REG_RA); /* Return address register. */
+ DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4); /* Augmentation data. */
+ DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t));
+ DB(DW_CFA_offset|DW_REG_RA); DUV(1);
+ DALIGNNOP(sizeof(uintptr_t));
+ )
+
+ /* DWARF EH FDE (Frame Description Entry). */
+ DSECT(FDE,
+ DU32((uint32_t)(p-framep)); /* Offset to CIE Pointer. */
+ DU32(0); /* Machine code offset relative to .text. */
+ DU32(ctx->szmcode); /* Machine code length. */
+ DB(0); /* Augmentation data. */
+ DB(DW_CFA_def_cfa_offset); DUV(sizeof(uintptr_t));
+#if defined(__i386__)
+ DB(DW_CFA_advance_loc|3); /* sub $0xc,%esp */
+ DB(DW_CFA_def_cfa_offset); DUV(16); /* Aligned stack frame size. */
+#elif defined(__x86_64__)
+ DB(DW_CFA_advance_loc|4); /* sub $0x8,%rsp */
+ DB(DW_CFA_def_cfa_offset); DUV(16); /* Aligned stack frame size. */
+#else
+# error "Unsupported target architecture"
+#endif
+ DALIGNNOP(sizeof(uintptr_t));
+ )
+
+ ctx->p = p;
+}
+
+static void zend_gdbjit_debuginfo(zend_gdbjit_ctx *ctx)
+{
+ uint8_t *p = ctx->p;
+
+ DSECT(info,
+ DU16(2); /* DWARF version. */
+ DU32(0); /* Abbrev offset. */
+ DB(sizeof(uintptr_t)); /* Pointer size. */
+
+ DUV(1); /* Abbrev #1: DW_TAG_compile_unit. */
+ DSTR(ctx->filename); /* DW_AT_name. */
+ DADDR(ctx->mcaddr); /* DW_AT_low_pc. */
+ DADDR(ctx->mcaddr + ctx->szmcode); /* DW_AT_high_pc. */
+ DU32(0); /* DW_AT_stmt_list. */
+ );
+
+ ctx->p = p;
+}
+
+static void zend_gdbjit_debugabbrev(zend_gdbjit_ctx *ctx)
+{
+ uint8_t *p = ctx->p;
+
+ /* Abbrev #1: DW_TAG_compile_unit. */
+ DUV(1);
+ DUV(DW_TAG_compile_unit);
+ DB(DW_children_no);
+ DUV(DW_AT_name);
+ DUV(DW_FORM_string);
+ DUV(DW_AT_low_pc);
+ DUV(DW_FORM_addr);
+ DUV(DW_AT_high_pc);
+ DUV(DW_FORM_addr);
+ DUV(DW_AT_stmt_list);
+ DUV(DW_FORM_data4);
+ DB(0);
+ DB(0);
+
+ ctx->p = p;
+}
+
+#define DLNE(op, s) (DB(DW_LNS_extended_op), DUV(1+(s)), DB((op)))
+
+static void zend_gdbjit_debugline(zend_gdbjit_ctx *ctx)
+{
+ uint8_t *p = ctx->p;
+
+ DSECT(line,
+ DU16(2); /* DWARF version. */
+ DSECT(header,
+ DB(1); /* Minimum instruction length. */
+ DB(1); /* is_stmt. */
+ DI8(0); /* Line base for special opcodes. */
+ DB(2); /* Line range for special opcodes. */
+ DB(3+1); /* Opcode base at DW_LNS_advance_line+1. */
+ DB(0); DB(1); DB(1); /* Standard opcode lengths. */
+ /* Directory table. */
+ DB(0);
+ /* File name table. */
+ DSTR(ctx->filename); DUV(0); DUV(0); DUV(0);
+ DB(0);
+ );
+ DLNE(DW_LNE_set_address, sizeof(uintptr_t));
+ DADDR(ctx->mcaddr);
+ if (ctx->lineno) (DB(DW_LNS_advance_line), DSV(ctx->lineno-1));
+ DB(DW_LNS_copy);
+ DB(DW_LNS_advance_pc); DUV(ctx->szmcode);
+ DLNE(DW_LNE_end_sequence, 0);
+ );
+
+ ctx->p = p;
+}
+
+
+#undef DLNE
+
+/* Undef shortcuts. */
+#undef DB
+#undef DI8
+#undef DU16
+#undef DU32
+#undef DADDR
+#undef DUV
+#undef DSV
+#undef DSTR
+#undef DALIGNNOP
+#undef DSECT
+
+typedef void (*zend_gdbjit_initf) (zend_gdbjit_ctx *ctx);
+
+static void zend_gdbjit_initsect(zend_gdbjit_ctx *ctx, int sect, zend_gdbjit_initf initf)
+{
+ ctx->startp = ctx->p;
+ ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj);
+ initf(ctx);
+ ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp);
+}
+
+static void zend_gdbjit_buildobj(zend_gdbjit_ctx *ctx)
+{
+ zend_gdbjit_obj *obj = &ctx->obj;
+
+ /* Fill in ELF header and clear structures. */
+ memcpy(&obj->hdr, &zend_elfhdr_template, sizeof(zend_elf_header));
+ memset(&obj->sect, 0, sizeof(zend_elf_sectheader) * GDBJIT_SECT__MAX);
+ memset(&obj->sym, 0, sizeof(zend_elf_symbol) * GDBJIT_SYM__MAX);
+
+ /* Initialize sections. */
+ ctx->p = obj->space;
+ zend_gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab, zend_gdbjit_secthdr);
+ zend_gdbjit_initsect(ctx, GDBJIT_SECT_strtab, zend_gdbjit_symtab);
+ zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_info, zend_gdbjit_debuginfo);
+ zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev, zend_gdbjit_debugabbrev);
+ zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_line, zend_gdbjit_debugline);
+ SECTALIGN(ctx->p, sizeof(uintptr_t));
+ zend_gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame, zend_gdbjit_ehframe);
+ ctx->objsize = (size_t)((char *)ctx->p - (char *)obj);
+
+ ZEND_ASSERT(ctx->objsize < sizeof(zend_gdbjit_obj));
+}
+
+static int zend_jit_gdb_register(const char *name,
+ const zend_op_array *op_array,
+ const void *start,
+ size_t size)
+{
+ zend_gdbjit_ctx ctx;
+
+ ctx.mcaddr = (uintptr_t)start;
+ ctx.szmcode = (uint32_t)size;
+ ctx.name = name;
+ ctx.filename = op_array ? ZSTR_VAL(op_array->filename) : "unknown";
+ ctx.lineno = op_array ? op_array->line_start : 0;
+
+ zend_gdbjit_buildobj(&ctx);
+
+ return zend_gdb_register_code(&ctx.obj, ctx.objsize);
+}
+
+static int zend_jit_gdb_unregister(void)
+{
+ zend_gdb_unregister_all();
+ return 1;
+}
+
+static void zend_jit_gdb_init(void)
+{
+#if 0
+ /* This might enable registration of all JIT-ed code, but unfortunately,
+ * in case of many functions, this takes enormous time. */
+ if (zend_gdb_present()) {
+ ZCG(accel_directives).jit_debug |= ZEND_JIT_DEBUG_GDB;
+ }
+#endif
+}
+
+#endif
diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c
new file mode 100644
index 0000000000..d0caabe5da
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_helpers.c
@@ -0,0 +1,1504 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "Zend/zend_API.h"
+
+static ZEND_COLD void undef_result_after_exception() {
+ const zend_op *opline = EG(opline_before_exception);
+ ZEND_ASSERT(EG(exception));
+ if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
+ zend_execute_data *execute_data = EG(current_execute_data);
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ }
+}
+
+static zend_never_inline zend_function* ZEND_FASTCALL _zend_jit_init_func_run_time_cache(const zend_op_array *op_array) /* {{{ */
+{
+ void **run_time_cache;
+
+ run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
+ memset(run_time_cache, 0, op_array->cache_size);
+ ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
+ return (zend_function*)op_array;
+}
+/* }}} */
+
+static zend_never_inline zend_op_array* ZEND_FASTCALL zend_jit_init_func_run_time_cache_helper(zend_op_array *op_array) /* {{{ */
+{
+ void **run_time_cache;
+
+ if (!RUN_TIME_CACHE(op_array)) {
+ run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
+ memset(run_time_cache, 0, op_array->cache_size);
+ ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
+ }
+ return op_array;
+}
+/* }}} */
+
+static zend_function* ZEND_FASTCALL zend_jit_find_func_helper(zend_string *name)
+{
+ zval *func = zend_hash_find_ex(EG(function_table), name, 1);
+ zend_function *fbc;
+
+ if (UNEXPECTED(func == NULL)) {
+ return NULL;
+ }
+ fbc = Z_FUNC_P(func);
+ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) {
+ fbc = _zend_jit_init_func_run_time_cache(&fbc->op_array);
+ }
+ return fbc;
+}
+
+static zend_execute_data* ZEND_FASTCALL zend_jit_extend_stack_helper(uint32_t used_stack, zend_function *fbc)
+{
+ zend_execute_data *call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
+ call->func = fbc;
+ ZEND_CALL_INFO(call) = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_ALLOCATED;
+ return call;
+}
+
+static zend_execute_data* ZEND_FASTCALL zend_jit_int_extend_stack_helper(uint32_t used_stack)
+{
+ zend_execute_data *call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
+ ZEND_CALL_INFO(call) = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_ALLOCATED;
+ return call;
+}
+
+static zval* ZEND_FASTCALL zend_jit_symtable_find(HashTable *ht, zend_string *str)
+{
+ zend_ulong idx;
+ register const char *tmp = str->val;
+
+ do {
+ if (*tmp > '9') {
+ break;
+ } else if (*tmp < '0') {
+ if (*tmp != '-') {
+ break;
+ }
+ tmp++;
+ if (*tmp > '9' || *tmp < '0') {
+ break;
+ }
+ }
+ if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
+ return zend_hash_index_find(ht, idx);
+ }
+ } while (0);
+
+ return zend_hash_find(ht, str);
+}
+
+static zval* ZEND_FASTCALL zend_jit_hash_index_lookup_rw(HashTable *ht, zend_long idx)
+{
+ zval *retval = zend_hash_index_find(ht, idx);
+
+ if (!retval) {
+ zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, idx);
+ retval = zend_hash_index_update(ht, idx, &EG(uninitialized_zval));
+ }
+ return retval;
+}
+
+static zval* ZEND_FASTCALL zend_jit_hash_index_lookup_w(HashTable *ht, zend_long idx)
+{
+ zval *retval = zend_hash_index_find(ht, idx);
+
+ if (!retval) {
+ retval = zend_hash_index_add_new(ht, idx, &EG(uninitialized_zval));
+ }
+ return retval;
+}
+
+static zval* ZEND_FASTCALL zend_jit_hash_lookup_rw(HashTable *ht, zend_string *str)
+{
+ zval *retval = zend_hash_find(ht, str);
+
+ if (retval) {
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
+ retval = Z_INDIRECT_P(retval);
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
+ zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(str));
+ ZVAL_NULL(retval);
+ }
+ }
+ } else {
+ zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(str));
+ retval = zend_hash_update(ht, str, &EG(uninitialized_zval));
+ }
+ return retval;
+}
+
+static zval* ZEND_FASTCALL zend_jit_hash_lookup_w(HashTable *ht, zend_string *str)
+{
+ zval *retval = zend_hash_find(ht, str);
+
+ if (retval) {
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
+ retval = Z_INDIRECT_P(retval);
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
+ ZVAL_NULL(retval);
+ }
+ }
+ } else {
+ retval = zend_hash_add_new(ht, str, &EG(uninitialized_zval));
+ }
+ return retval;
+}
+
+static zval* ZEND_FASTCALL zend_jit_symtable_lookup_rw(HashTable *ht, zend_string *str)
+{
+ zend_ulong idx;
+ register const char *tmp = str->val;
+
+ do {
+ if (*tmp > '9') {
+ break;
+ } else if (*tmp < '0') {
+ if (*tmp != '-') {
+ break;
+ }
+ tmp++;
+ if (*tmp > '9' || *tmp < '0') {
+ break;
+ }
+ }
+ if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
+ zval *retval = zend_hash_index_find(ht, idx);
+
+ if (!retval) {
+ zend_error(E_NOTICE,"Undefined index: %s", ZSTR_VAL(str));
+ retval = zend_hash_index_update(ht, idx, &EG(uninitialized_zval));
+ }
+ return retval;
+ }
+ } while (0);
+
+ return zend_jit_hash_lookup_rw(ht, str);
+}
+
+static zval* ZEND_FASTCALL zend_jit_symtable_lookup_w(HashTable *ht, zend_string *str)
+{
+ zend_ulong idx;
+ register const char *tmp = str->val;
+
+ do {
+ if (*tmp > '9') {
+ break;
+ } else if (*tmp < '0') {
+ if (*tmp != '-') {
+ break;
+ }
+ tmp++;
+ if (*tmp > '9' || *tmp < '0') {
+ break;
+ }
+ }
+ if (_zend_handle_numeric_str_ex(str->val, str->len, &idx)) {
+ zval *retval = zend_hash_index_find(ht, idx);
+
+ if (!retval) {
+ retval = zend_hash_index_add_new(ht, idx, &EG(uninitialized_zval));
+ }
+ return retval;
+ }
+ } while (0);
+
+ return zend_jit_hash_lookup_w(ht, str);
+}
+
+static void ZEND_FASTCALL zend_jit_undefined_op_helper(uint32_t var)
+{
+ const zend_execute_data *execute_data = EG(current_execute_data);
+ zend_string *cv = EX(func)->op_array.vars[EX_VAR_TO_NUM(var)];
+
+ zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(cv));
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_dim_r_helper(zend_array *ht, zval *dim, zval *result)
+{
+ zend_long hval;
+ zend_string *offset_key;
+ zval *retval;
+
+ if (Z_TYPE_P(dim) == IS_REFERENCE) {
+ dim = Z_REFVAL_P(dim);
+ }
+
+ switch (Z_TYPE_P(dim)) {
+ case IS_LONG:
+ hval = Z_LVAL_P(dim);
+ goto num_index;
+ case IS_STRING:
+ offset_key = Z_STR_P(dim);
+ goto str_index;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ /* break missing intentionally */
+ case IS_NULL:
+ offset_key = ZSTR_EMPTY_ALLOC();
+ goto str_index;
+ case IS_DOUBLE:
+ hval = zend_dval_to_lval(Z_DVAL_P(dim));
+ goto num_index;
+ case IS_RESOURCE:
+ zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
+ hval = Z_RES_HANDLE_P(dim);
+ goto num_index;
+ case IS_FALSE:
+ hval = 0;
+ goto num_index;
+ case IS_TRUE:
+ hval = 1;
+ goto num_index;
+ default:
+ zend_type_error("Illegal offset type");
+ ZVAL_NULL(result);
+ return;
+ }
+
+str_index:
+ retval = zend_hash_find(ht, offset_key);
+ if (retval) {
+ /* support for $GLOBALS[...] */
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
+ retval = Z_INDIRECT_P(retval);
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
+ zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
+ ZVAL_NULL(result);
+ return;
+ }
+ }
+ } else {
+ zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
+ ZVAL_NULL(result);
+ return;
+ }
+ ZVAL_COPY_DEREF(result, retval);
+ return;
+
+num_index:
+ ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ ZVAL_COPY_DEREF(result, retval);
+ return;
+
+num_undef:
+ zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ ZVAL_NULL(result);
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_dim_is_helper(zend_array *ht, zval *dim, zval *result)
+{
+ zend_long hval;
+ zend_string *offset_key;
+ zval *retval;
+
+ if (Z_TYPE_P(dim) == IS_REFERENCE) {
+ dim = Z_REFVAL_P(dim);
+ }
+
+ switch (Z_TYPE_P(dim)) {
+ case IS_LONG:
+ hval = Z_LVAL_P(dim);
+ goto num_index;
+ case IS_STRING:
+ offset_key = Z_STR_P(dim);
+ goto str_index;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ /* break missing intentionally */
+ case IS_NULL:
+ offset_key = ZSTR_EMPTY_ALLOC();
+ goto str_index;
+ case IS_DOUBLE:
+ hval = zend_dval_to_lval(Z_DVAL_P(dim));
+ goto num_index;
+ case IS_RESOURCE:
+ zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
+ hval = Z_RES_HANDLE_P(dim);
+ goto num_index;
+ case IS_FALSE:
+ hval = 0;
+ goto num_index;
+ case IS_TRUE:
+ hval = 1;
+ goto num_index;
+ default:
+ zend_type_error("Illegal offset type");
+ ZVAL_NULL(result);
+ return;
+ }
+
+str_index:
+ retval = zend_hash_find(ht, offset_key);
+ if (retval) {
+ /* support for $GLOBALS[...] */
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
+ retval = Z_INDIRECT_P(retval);
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
+ ZVAL_NULL(result);
+ return;
+ }
+ }
+ } else {
+ ZVAL_NULL(result);
+ return;
+ }
+ ZVAL_COPY_DEREF(result, retval);
+ return;
+
+num_index:
+ ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ ZVAL_COPY_DEREF(result, retval);
+ return;
+
+num_undef:
+ ZVAL_NULL(result);
+}
+
+static int ZEND_FASTCALL zend_jit_fetch_dim_isset_helper(zend_array *ht, zval *dim)
+{
+ zend_long hval;
+ zend_string *offset_key;
+ zval *retval;
+
+ if (Z_TYPE_P(dim) == IS_REFERENCE) {
+ dim = Z_REFVAL_P(dim);
+ }
+
+ switch (Z_TYPE_P(dim)) {
+ case IS_LONG:
+ hval = Z_LVAL_P(dim);
+ goto num_index;
+ case IS_STRING:
+ offset_key = Z_STR_P(dim);
+ goto str_index;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ /* break missing intentionally */
+ case IS_NULL:
+ offset_key = ZSTR_EMPTY_ALLOC();
+ goto str_index;
+ case IS_DOUBLE:
+ hval = zend_dval_to_lval(Z_DVAL_P(dim));
+ goto num_index;
+ case IS_RESOURCE:
+ zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
+ hval = Z_RES_HANDLE_P(dim);
+ goto num_index;
+ case IS_FALSE:
+ hval = 0;
+ goto num_index;
+ case IS_TRUE:
+ hval = 1;
+ goto num_index;
+ default:
+ zend_type_error("Illegal offset type in isset or empty");
+ return 0;
+ }
+
+str_index:
+ retval = zend_hash_find(ht, offset_key);
+ if (retval) {
+ /* support for $GLOBALS[...] */
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
+ retval = Z_INDIRECT_P(retval);
+ }
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_REFERENCE)) {
+ retval = Z_REFVAL_P(retval);
+ }
+ return (Z_TYPE_P(retval) > IS_NULL);
+ } else {
+ return 0;
+ }
+
+num_index:
+ ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_REFERENCE)) {
+ retval = Z_REFVAL_P(retval);
+ }
+ return (Z_TYPE_P(retval) > IS_NULL);
+
+num_undef:
+ return 0;
+}
+
+static zval* ZEND_FASTCALL zend_jit_fetch_dim_rw_helper(zend_array *ht, zval *dim)
+{
+ zend_long hval;
+ zend_string *offset_key;
+ zval *retval;
+
+ if (Z_TYPE_P(dim) == IS_REFERENCE) {
+ dim = Z_REFVAL_P(dim);
+ }
+
+ switch (Z_TYPE_P(dim)) {
+ case IS_LONG:
+ hval = Z_LVAL_P(dim);
+ goto num_index;
+ case IS_STRING:
+ offset_key = Z_STR_P(dim);
+ goto str_index;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ /* break missing intentionally */
+ case IS_NULL:
+ offset_key = ZSTR_EMPTY_ALLOC();
+ goto str_index;
+ case IS_DOUBLE:
+ hval = zend_dval_to_lval(Z_DVAL_P(dim));
+ goto num_index;
+ case IS_RESOURCE:
+ zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
+ hval = Z_RES_HANDLE_P(dim);
+ goto num_index;
+ case IS_FALSE:
+ hval = 0;
+ goto num_index;
+ case IS_TRUE:
+ hval = 1;
+ goto num_index;
+ default:
+ zend_type_error("Illegal offset type");
+ undef_result_after_exception();
+ return NULL;
+ }
+
+str_index:
+ retval = zend_hash_find(ht, offset_key);
+ if (retval) {
+ /* support for $GLOBALS[...] */
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
+ retval = Z_INDIRECT_P(retval);
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
+ zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
+ ZVAL_NULL(retval);
+ }
+ }
+ } else {
+ zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
+ retval = zend_hash_update(ht, offset_key, &EG(uninitialized_zval));
+ }
+ return retval;
+
+num_index:
+ ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ return retval;
+
+num_undef:
+ zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
+ return retval;
+}
+
+static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim)
+{
+ zend_long hval;
+ zend_string *offset_key;
+ zval *retval;
+
+ if (Z_TYPE_P(dim) == IS_REFERENCE) {
+ dim = Z_REFVAL_P(dim);
+ }
+
+ switch (Z_TYPE_P(dim)) {
+ case IS_LONG:
+ hval = Z_LVAL_P(dim);
+ goto num_index;
+ case IS_STRING:
+ offset_key = Z_STR_P(dim);
+ goto str_index;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ /* break missing intentionally */
+ case IS_NULL:
+ offset_key = ZSTR_EMPTY_ALLOC();
+ goto str_index;
+ case IS_DOUBLE:
+ hval = zend_dval_to_lval(Z_DVAL_P(dim));
+ goto num_index;
+ case IS_RESOURCE:
+ zend_error(E_WARNING, "Resource ID#%d used as offset, casting to integer (%d)", Z_RES_HANDLE_P(dim), Z_RES_HANDLE_P(dim));
+ hval = Z_RES_HANDLE_P(dim);
+ goto num_index;
+ case IS_FALSE:
+ hval = 0;
+ goto num_index;
+ case IS_TRUE:
+ hval = 1;
+ goto num_index;
+ default:
+ zend_type_error("Illegal offset type");
+ undef_result_after_exception();
+ return NULL;
+ }
+
+str_index:
+ retval = zend_hash_find(ht, offset_key);
+ if (retval) {
+ /* support for $GLOBALS[...] */
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
+ retval = Z_INDIRECT_P(retval);
+ if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
+ ZVAL_NULL(retval);
+ }
+ }
+ } else {
+ retval = zend_hash_add_new(ht, offset_key, &EG(uninitialized_zval));
+ }
+ return retval;
+
+num_index:
+ ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ return retval;
+
+num_undef:
+ retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
+ return retval;
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_dim_str_r_helper(zval *container, zval *dim, zval *result)
+{
+ zend_long offset;
+
+try_string_offset:
+ if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
+ switch (Z_TYPE_P(dim)) {
+ /* case IS_LONG: */
+ case IS_STRING:
+ if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
+ break;
+ }
+ zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
+ break;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ case IS_DOUBLE:
+ case IS_NULL:
+ case IS_FALSE:
+ case IS_TRUE:
+ zend_error(E_WARNING, "String offset cast occurred");
+ break;
+ case IS_REFERENCE:
+ dim = Z_REFVAL_P(dim);
+ goto try_string_offset;
+ default:
+ zend_type_error("Illegal offset type");
+ break;
+ }
+
+ offset = _zval_get_long_func(dim);
+ } else {
+ offset = Z_LVAL_P(dim);
+ }
+
+ if (UNEXPECTED(Z_STRLEN_P(container) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
+ zend_error(E_WARNING, "Uninitialized string offset: " ZEND_LONG_FMT, offset);
+ ZVAL_EMPTY_STRING(result);
+ } else {
+ zend_uchar c;
+ zend_long real_offset;
+
+ real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
+ ? (zend_long)Z_STRLEN_P(container) + offset : offset;
+ c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
+ ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zval *container, zval *dim, zval *result)
+{
+ zend_long offset;
+
+try_string_offset:
+ if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
+ switch (Z_TYPE_P(dim)) {
+ /* case IS_LONG: */
+ case IS_STRING:
+ if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
+ break;
+ }
+ ZVAL_NULL(result);
+ return;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ case IS_DOUBLE:
+ case IS_NULL:
+ case IS_FALSE:
+ case IS_TRUE:
+ break;
+ case IS_REFERENCE:
+ dim = Z_REFVAL_P(dim);
+ goto try_string_offset;
+ default:
+ zend_type_error("Illegal offset type");
+ break;
+ }
+
+ offset = _zval_get_long_func(dim);
+ } else {
+ offset = Z_LVAL_P(dim);
+ }
+
+ if (UNEXPECTED(Z_STRLEN_P(container) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
+ ZVAL_NULL(result);
+ } else {
+ zend_uchar c;
+ zend_long real_offset;
+
+ real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
+ ? (zend_long)Z_STRLEN_P(container) + offset : offset;
+ c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
+ ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_dim_obj_r_helper(zval *container, zval *dim, zval *result)
+{
+ zval *retval;
+
+ if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ dim = &EG(uninitialized_zval);
+ }
+
+ retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, BP_VAR_R, result);
+
+ if (retval) {
+ if (result != retval) {
+ ZVAL_COPY_DEREF(result, retval);
+ } else if (UNEXPECTED(Z_ISREF_P(retval))) {
+ zend_unwrap_reference(retval);
+ }
+ } else {
+ ZVAL_NULL(result);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval *dim, zval *result)
+{
+ zval *retval;
+
+ if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ dim = &EG(uninitialized_zval);
+ }
+
+ retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, BP_VAR_IS, result);
+
+ if (retval) {
+ if (result != retval) {
+ ZVAL_COPY_DEREF(result, retval);
+ } else if (UNEXPECTED(Z_ISREF_P(retval))) {
+ zend_unwrap_reference(result);
+ }
+ } else {
+ ZVAL_NULL(result);
+ }
+}
+
+static zval* ZEND_FASTCALL zend_jit_fetch_dimension_rw_long_helper(HashTable *ht, zend_long hval)
+{
+ zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ return zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
+}
+
+static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type)
+{
+ zend_long offset;
+
+try_again:
+ if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
+ switch(Z_TYPE_P(dim)) {
+ case IS_STRING:
+ if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, -1)) {
+ break;
+ }
+ if (type != BP_VAR_UNSET) {
+ zend_error(E_WARNING, "Illegal string offset '%s'", Z_STRVAL_P(dim));
+ }
+ break;
+ case IS_UNDEF:
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ case IS_DOUBLE:
+ case IS_NULL:
+ case IS_FALSE:
+ case IS_TRUE:
+ zend_error(E_WARNING, "String offset cast occurred");
+ break;
+ case IS_REFERENCE:
+ dim = Z_REFVAL_P(dim);
+ goto try_again;
+ default:
+ zend_type_error("Illegal offset type");
+ break;
+ }
+
+ offset = _zval_get_long_func(dim);
+ } else {
+ offset = Z_LVAL_P(dim);
+ }
+
+ return offset;
+}
+
+static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void)
+{
+ const char *msg = NULL;
+ const zend_op *opline = EG(current_execute_data)->opline;
+ const zend_op *end;
+ uint32_t var;
+
+ switch (opline->opcode) {
+ case ZEND_ASSIGN_OP:
+ case ZEND_ASSIGN_DIM_OP:
+ case ZEND_ASSIGN_OBJ_OP:
+ case ZEND_ASSIGN_STATIC_PROP_OP:
+ msg = "Cannot use assign-op operators with string offsets";
+ break;
+ case ZEND_FETCH_DIM_W:
+ case ZEND_FETCH_DIM_RW:
+ case ZEND_FETCH_DIM_FUNC_ARG:
+ case ZEND_FETCH_DIM_UNSET:
+ /* TODO: Encode the "reason" into opline->extended_value??? */
+ var = opline->result.var;
+ opline++;
+ end = EG(current_execute_data)->func->op_array.opcodes +
+ EG(current_execute_data)->func->op_array.last;
+ while (opline < end) {
+ if (opline->op1_type == IS_VAR && opline->op1.var == var) {
+ switch (opline->opcode) {
+ case ZEND_ASSIGN_OBJ_OP:
+ msg = "Cannot use string offset as an object";
+ break;
+ case ZEND_ASSIGN_DIM_OP:
+ msg = "Cannot use string offset as an array";
+ break;
+ case ZEND_ASSIGN_OP:
+ case ZEND_ASSIGN_STATIC_PROP_OP:
+ msg = "Cannot use assign-op operators with string offsets";
+ break;
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ msg = "Cannot increment/decrement string offsets";
+ break;
+ case ZEND_FETCH_DIM_W:
+ case ZEND_FETCH_DIM_RW:
+ case ZEND_FETCH_DIM_FUNC_ARG:
+ case ZEND_FETCH_DIM_UNSET:
+ case ZEND_ASSIGN_DIM:
+ msg = "Cannot use string offset as an array";
+ break;
+ case ZEND_FETCH_OBJ_W:
+ case ZEND_FETCH_OBJ_RW:
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ case ZEND_FETCH_OBJ_UNSET:
+ case ZEND_ASSIGN_OBJ:
+ msg = "Cannot use string offset as an object";
+ break;
+ case ZEND_ASSIGN_REF:
+ case ZEND_ADD_ARRAY_ELEMENT:
+ case ZEND_INIT_ARRAY:
+ case ZEND_MAKE_REF:
+ msg = "Cannot create references to/from string offsets";
+ break;
+ case ZEND_RETURN_BY_REF:
+ case ZEND_VERIFY_RETURN_TYPE:
+ msg = "Cannot return string offsets by reference";
+ break;
+ case ZEND_UNSET_DIM:
+ case ZEND_UNSET_OBJ:
+ msg = "Cannot unset string offsets";
+ break;
+ case ZEND_YIELD:
+ msg = "Cannot yield string offsets by reference";
+ break;
+ case ZEND_SEND_REF:
+ case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_FUNC_ARG:
+ msg = "Only variables can be passed by reference";
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ break;
+ }
+ if (opline->op2_type == IS_VAR && opline->op2.var == var) {
+ ZEND_ASSERT(opline->opcode == ZEND_ASSIGN_REF);
+ msg = "Cannot create references to/from string offsets";
+ break;
+ }
+ }
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE();
+ }
+ ZEND_ASSERT(msg != NULL);
+ zend_throw_error(NULL, "%s", msg);
+}
+
+static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result)
+{
+ zend_string *old_str;
+ zend_uchar c;
+ size_t string_len;
+ zend_long offset;
+
+ offset = zend_check_string_offset(dim, BP_VAR_W);
+ if (offset < -(zend_long)Z_STRLEN_P(str)) {
+ /* Error on negative offset */
+ zend_error(E_WARNING, "Illegal string offset: " ZEND_LONG_FMT, offset);
+ if (result) {
+ ZVAL_NULL(result);
+ }
+ return;
+ }
+
+ if (Z_TYPE_P(value) != IS_STRING) {
+ /* Convert to string, just the time to pick the 1st byte */
+ zend_string *tmp = zval_try_get_string_func(value);
+
+ if (UNEXPECTED(!tmp)) {
+ if (result) {
+ ZVAL_UNDEF(result);
+ }
+ return;
+ }
+
+ string_len = ZSTR_LEN(tmp);
+ c = (zend_uchar)ZSTR_VAL(tmp)[0];
+ zend_string_release(tmp);
+ } else {
+ string_len = Z_STRLEN_P(value);
+ c = (zend_uchar)Z_STRVAL_P(value)[0];
+ }
+
+
+ if (string_len != 1) {
+ if (string_len == 0) {
+ /* Error on empty input string */
+ zend_throw_error(NULL, "Cannot assign an empty string to a string offset");
+ if (result) {
+ ZVAL_NULL(result);
+ }
+ return;
+ }
+
+ zend_error(E_WARNING, "Only the first byte will be assigned to the string offset");
+ }
+
+ if (offset < 0) { /* Handle negative offset */
+ offset += (zend_long)Z_STRLEN_P(str);
+ }
+
+ if ((size_t)offset >= Z_STRLEN_P(str)) {
+ /* Extend string if needed */
+ zend_long old_len = Z_STRLEN_P(str);
+ Z_STR_P(str) = zend_string_extend(Z_STR_P(str), offset + 1, 0);
+ Z_TYPE_INFO_P(str) = IS_STRING_EX;
+ memset(Z_STRVAL_P(str) + old_len, ' ', offset - old_len);
+ Z_STRVAL_P(str)[offset+1] = 0;
+ } else if (!Z_REFCOUNTED_P(str)) {
+ old_str = Z_STR_P(str);
+ Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
+ Z_TYPE_INFO_P(str) = IS_STRING_EX;
+ zend_string_release(old_str);
+ } else {
+ SEPARATE_STRING(str);
+ zend_string_forget_hash_val(Z_STR_P(str));
+ }
+
+ Z_STRVAL_P(str)[offset] = c;
+
+ if (result) {
+ /* Return the new character */
+ ZVAL_INTERNED_STR(result, ZSTR_CHAR(c));
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim, zval *value, zval *result)
+{
+ if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
+ ZVAL_DEREF(value);
+ Z_OBJ_HT_P(object_ptr)->write_dimension(Z_OBJ_P(object_ptr), dim, value);
+ if (result) {
+ if (EXPECTED(!EG(exception))) {
+ ZVAL_COPY(result, value);
+ } else {
+ ZVAL_UNDEF(result);
+ }
+ }
+ } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
+ if (!dim) {
+ zend_throw_error(NULL, "[] operator not supported for strings");
+ if (result) {
+ ZVAL_UNDEF(result);
+ }
+ } else {
+ zend_assign_to_string_offset(object_ptr, dim, value, result);
+ }
+ } else {
+ zend_throw_error(NULL, "Cannot use a scalar value as an array");
+ if (result) {
+ ZVAL_UNDEF(result);
+ }
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *dim, zval *value, binary_op_type binary_op)
+{
+ if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ zval *object = container;
+ zval *property = dim;
+ zval *z;
+ zval rv, res;
+
+ z = Z_OBJ_HT_P(object)->read_dimension(Z_OBJ_P(object), property, BP_VAR_R, &rv);
+ if (z != NULL) {
+
+ if (binary_op(&res, Z_ISREF_P(z) ? Z_REFVAL_P(z) : z, value) == SUCCESS) {
+ Z_OBJ_HT_P(object)->write_dimension(Z_OBJ_P(object), property, &res);
+ }
+ if (z == &rv) {
+ zval_ptr_dtor(&rv);
+ }
+//??? if (retval) {
+//??? ZVAL_COPY(retval, &res);
+//??? }
+ zval_ptr_dtor(&res);
+ } else {
+ zend_error(E_WARNING, "Attempt to assign property of non-object");
+//??? if (retval) {
+//??? ZVAL_NULL(retval);
+//??? }
+ }
+ } else {
+ if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
+ if (!dim) {
+ zend_throw_error(NULL, "[] operator not supported for strings");
+ } else {
+ zend_check_string_offset(dim, BP_VAR_RW);
+ zend_wrong_string_offset();
+ }
+//??? } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
+//??? ZEND_VM_C_GOTO(assign_dim_op_convert_to_array);
+ } else {
+ zend_throw_error(NULL, "Cannot use a scalar value as an array");
+//??? if (retval) {
+//??? ZVAL_NULL(retval);
+//??? }
+ }
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_fast_assign_concat_helper(zval *op1, zval *op2)
+{
+ size_t op1_len = Z_STRLEN_P(op1);
+ size_t op2_len = Z_STRLEN_P(op2);
+ size_t result_len = op1_len + op2_len;
+ zend_string *result_str;
+
+ if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
+ zend_throw_error(NULL, "String size overflow");
+ return;
+ }
+
+ if (Z_REFCOUNTED_P(op1)) {
+ result_str = zend_string_extend(Z_STR_P(op1), result_len, 0);
+ } else {
+ result_str = zend_string_alloc(result_len, 0);
+ memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
+ }
+
+ ZVAL_NEW_STR(op1, result_str);
+
+ memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
+ ZSTR_VAL(result_str)[result_len] = '\0';
+}
+
+static void ZEND_FASTCALL zend_jit_fast_concat_helper(zval *result, zval *op1, zval *op2)
+{
+ size_t op1_len = Z_STRLEN_P(op1);
+ size_t op2_len = Z_STRLEN_P(op2);
+ size_t result_len = op1_len + op2_len;
+ zend_string *result_str;
+
+ if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
+ zend_throw_error(NULL, "String size overflow");
+ return;
+ }
+
+ result_str = zend_string_alloc(result_len, 0);
+ memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
+
+ ZVAL_NEW_STR(result, result_str);
+
+ memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
+ ZSTR_VAL(result_str)[result_len] = '\0';
+}
+
+static int ZEND_FASTCALL zend_jit_isset_dim_helper(zval *container, zval *offset)
+{
+ if (UNEXPECTED(Z_TYPE_P(offset) == IS_UNDEF)) {
+ zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
+ offset = &EG(uninitialized_zval);
+ }
+
+ if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
+ return Z_OBJ_HT_P(container)->has_dimension(Z_OBJ_P(container), offset, 0);
+ } else if (EXPECTED(Z_TYPE_P(container) == IS_STRING)) { /* string offsets */
+ zend_long lval;
+
+ if (EXPECTED(Z_TYPE_P(offset) == IS_LONG)) {
+ lval = Z_LVAL_P(offset);
+isset_str_offset:
+ if (UNEXPECTED(lval < 0)) { /* Handle negative offset */
+ lval += (zend_long)Z_STRLEN_P(container);
+ }
+ if (EXPECTED(lval >= 0) && (size_t)lval < Z_STRLEN_P(container)) {
+ return 1;
+ }
+ } else {
+ ZVAL_DEREF(offset);
+ if (Z_TYPE_P(offset) < IS_STRING /* simple scalar types */
+ || (Z_TYPE_P(offset) == IS_STRING /* or numeric string */
+ && IS_LONG == is_numeric_string(Z_STRVAL_P(offset), Z_STRLEN_P(offset), NULL, NULL, 0))) {
+ lval = zval_get_long(offset);
+ goto isset_str_offset;
+ }
+ }
+ }
+ return 0;
+}
+
+static void ZEND_FASTCALL zend_jit_free_call_frame(zend_execute_data *call)
+{
+ zend_vm_stack_free_call_frame(call);
+}
+
+static zval* ZEND_FASTCALL zend_jit_new_ref_helper(zval *value)
+{
+ zend_reference *ref = (zend_reference*)emalloc(sizeof(zend_reference));
+ GC_SET_REFCOUNT(ref, 1);
+ GC_TYPE_INFO(ref) = IS_REFERENCE;
+ ref->sources.ptr = NULL;
+ ZVAL_COPY_VALUE(&ref->val, value);
+ Z_REF_P(value) = ref;
+ Z_TYPE_INFO_P(value) = IS_REFERENCE_EX;
+
+ return value;
+}
+
+static zval* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_execute_data *execute_data, zval *varname, uint32_t cache_slot)
+{
+ uint32_t idx;
+ zval *value = zend_hash_find(&EG(symbol_table), Z_STR_P(varname));
+
+ if (UNEXPECTED(value == NULL)) {
+ value = zend_hash_add_new(&EG(symbol_table), Z_STR_P(varname), &EG(uninitialized_zval));
+ idx = (char*)value - (char*)EG(symbol_table).arData;
+ /* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
+ CACHE_PTR(cache_slot, (void*)(uintptr_t)(idx + 1));
+ } else {
+ idx = (char*)value - (char*)EG(symbol_table).arData;
+ /* Store "hash slot index" + 1 (NULL is a mark of uninitialized cache slot) */
+ CACHE_PTR(cache_slot, (void*)(uintptr_t)(idx + 1));
+ /* GLOBAL variable may be an INDIRECT pointer to CV */
+ if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT)) {
+ value = Z_INDIRECT_P(value);
+ if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
+ ZVAL_NULL(value);
+ }
+ }
+ }
+
+ if (UNEXPECTED(!Z_ISREF_P(value))) {
+ return zend_jit_new_ref_helper(value);
+ }
+
+ return value;
+}
+
+static zend_always_inline zend_bool zend_jit_verify_type_common(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info, void **cache_slot)
+{
+ uint32_t type_mask;
+
+ if (ZEND_TYPE_HAS_CLASS(arg_info->type) && Z_TYPE_P(arg) == IS_OBJECT) {
+ zend_class_entry *ce;
+ if (ZEND_TYPE_HAS_LIST(arg_info->type)) {
+ zend_type *list_type;
+ ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(arg_info->type), list_type) {
+ if (*cache_slot) {
+ ce = *cache_slot;
+ } else {
+ ce = zend_fetch_class(ZEND_TYPE_NAME(*list_type),
+ (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
+ if (!ce) {
+ cache_slot++;
+ continue;
+ }
+ *cache_slot = ce;
+ }
+ if (instanceof_function(Z_OBJCE_P(arg), ce)) {
+ return 1;
+ }
+ cache_slot++;
+ } ZEND_TYPE_LIST_FOREACH_END();
+ } else {
+ if (EXPECTED(*cache_slot)) {
+ ce = (zend_class_entry *) *cache_slot;
+ } else {
+ ce = zend_fetch_class(ZEND_TYPE_NAME(arg_info->type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
+ if (UNEXPECTED(!ce)) {
+ goto builtin_types;
+ }
+ *cache_slot = (void *) ce;
+ }
+ if (instanceof_function(Z_OBJCE_P(arg), ce)) {
+ return 1;
+ }
+ }
+ }
+
+builtin_types:
+ type_mask = ZEND_TYPE_FULL_MASK(arg_info->type);
+ if ((type_mask & MAY_BE_CALLABLE) && zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL)) {
+ return 1;
+ }
+ if ((type_mask & MAY_BE_ITERABLE) && zend_is_iterable(arg)) {
+ return 1;
+ }
+ if (zend_verify_scalar_type_hint(type_mask, arg, ZEND_ARG_USES_STRICT_TYPES(), /* is_internal */ 0)) {
+ return 1;
+ }
+ return 0;
+}
+
+static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, const zend_op_array *op_array, uint32_t arg_num, zend_arg_info *arg_info, void **cache_slot)
+{
+ if (UNEXPECTED(!zend_jit_verify_type_common(arg, op_array, arg_info, cache_slot))) {
+ zend_verify_arg_error((zend_function*)op_array, arg_info, arg_num, cache_slot, arg);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_array *op_array, zend_arg_info *arg_info, void **cache_slot)
+{
+ if (UNEXPECTED(!zend_jit_verify_type_common(arg, op_array, arg_info, cache_slot))) {
+ zend_verify_return_error((zend_function*)op_array, cache_slot, arg);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_zval_copy_deref_helper(zval *dst, zval *src)
+{
+ ZVAL_DEREF(src);
+ ZVAL_COPY(dst, src);
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_obj_r_slow(zend_object *zobj, zval *offset, zval *result, uint32_t cache_slot)
+{
+ zval *retval;
+ zend_execute_data *execute_data = EG(current_execute_data);
+ zend_string *name, *tmp_name;
+
+ name = zval_get_tmp_string(offset, &tmp_name);
+ retval = zobj->handlers->read_property(zobj, name, BP_VAR_R, CACHE_ADDR(cache_slot), result);
+ zend_tmp_string_release(tmp_name);
+ if (retval != result) {
+ ZVAL_COPY_DEREF(result, retval);
+ } else if (UNEXPECTED(Z_ISREF_P(retval))) {
+ zend_unwrap_reference(retval);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_obj_r_dynamic(zend_object *zobj, intptr_t prop_offset, zval *offset, zval *result, uint32_t cache_slot)
+{
+ if (zobj->properties) {
+ zval *retval;
+
+ if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
+ intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
+
+ if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
+ Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
+
+ if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
+ (EXPECTED(p->key == Z_STR_P(offset)) ||
+ (EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) &&
+ EXPECTED(p->key != NULL) &&
+ EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(offset)) &&
+ EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(offset), Z_STRLEN_P(offset)) == 0)))) {
+ ZVAL_COPY_DEREF(result, &p->val);
+ return;
+ }
+ }
+ CACHE_PTR_EX((void**)((char*)EG(current_execute_data)->run_time_cache + cache_slot) + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
+ }
+
+ retval = zend_hash_find(zobj->properties, Z_STR_P(offset));
+
+ if (EXPECTED(retval)) {
+ intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
+ CACHE_PTR_EX((void**)((char*)EG(current_execute_data)->run_time_cache + cache_slot) + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
+ ZVAL_COPY_DEREF(result, retval);
+ return;
+ }
+ }
+ zend_jit_fetch_obj_r_slow(zobj, offset, result, cache_slot);
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_obj_is_slow(zend_object *zobj, zval *offset, zval *result, uint32_t cache_slot)
+{
+ zval *retval;
+ zend_execute_data *execute_data = EG(current_execute_data);
+ zend_string *name, *tmp_name;
+
+ name = zval_get_tmp_string(offset, &tmp_name);
+ retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, CACHE_ADDR(cache_slot), result);
+ zend_tmp_string_release(tmp_name);
+ if (retval != result) {
+ ZVAL_COPY_DEREF(result, retval);
+ } else if (UNEXPECTED(Z_ISREF_P(retval))) {
+ zend_unwrap_reference(retval);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intptr_t prop_offset, zval *offset, zval *result, uint32_t cache_slot)
+{
+ if (zobj->properties) {
+ zval *retval;
+
+ if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
+ intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
+
+ if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
+ Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
+
+ if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) &&
+ (EXPECTED(p->key == Z_STR_P(offset)) ||
+ (EXPECTED(p->h == ZSTR_H(Z_STR_P(offset))) &&
+ EXPECTED(p->key != NULL) &&
+ EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(offset)) &&
+ EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(offset), Z_STRLEN_P(offset)) == 0)))) {
+ ZVAL_COPY_DEREF(result, &p->val);
+ return;
+ }
+ }
+ CACHE_PTR_EX((void**)((char*)EG(current_execute_data)->run_time_cache + cache_slot) + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
+ }
+
+ retval = zend_hash_find(zobj->properties, Z_STR_P(offset));
+
+ if (EXPECTED(retval)) {
+ intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
+ CACHE_PTR_EX((void**)((char*)EG(current_execute_data)->run_time_cache + cache_slot) + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
+ ZVAL_COPY(result, retval);
+ return;
+ }
+ }
+ zend_jit_fetch_obj_is_slow(zobj, offset, result, cache_slot);
+}
+
+static void ZEND_FASTCALL zend_jit_vm_stack_free_args_helper(zend_execute_data *call)
+{
+ zend_vm_stack_free_args(call);
+}
+
+static zend_always_inline void zend_jit_assign_to_typed_ref(zend_reference *ref, zval *value, zend_uchar value_type)
+{
+ zval variable;
+
+ ZVAL_REF(&variable, ref);
+ zend_assign_to_variable(&variable, value, value_type, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)));
+}
+
+static void ZEND_FASTCALL zend_jit_assign_const_to_typed_ref(zend_reference *ref, zval *value)
+{
+ zend_jit_assign_to_typed_ref(ref, value, IS_CONST);
+}
+
+static void ZEND_FASTCALL zend_jit_assign_tmp_to_typed_ref(zend_reference *ref, zval *value)
+{
+ zend_jit_assign_to_typed_ref(ref, value, IS_TMP_VAR);
+}
+
+static void ZEND_FASTCALL zend_jit_assign_var_to_typed_ref(zend_reference *ref, zval *value)
+{
+ zend_jit_assign_to_typed_ref(ref, value, IS_VAR);
+}
+
+static void ZEND_FASTCALL zend_jit_assign_cv_to_typed_ref(zend_reference *ref, zval *value)
+{
+ zend_jit_assign_to_typed_ref(ref, value, IS_CV);
+}
+
+
+static zend_property_info *zend_jit_get_prop_not_accepting_double(zend_reference *ref)
+{
+ zend_property_info *prop;
+ ZEND_REF_FOREACH_TYPE_SOURCES(ref, prop) {
+ if (!(ZEND_TYPE_FULL_MASK(prop->type) & MAY_BE_DOUBLE)) {
+ return prop;
+ }
+ } ZEND_REF_FOREACH_TYPE_SOURCES_END();
+ return NULL;
+}
+
+static ZEND_COLD void zend_jit_throw_incdec_ref_error(zend_reference *ref, zend_bool inc)
+{
+ zend_property_info *error_prop = zend_jit_get_prop_not_accepting_double(ref);
+ /* Currently there should be no way for a typed reference to accept both int and double.
+ * Generalize this and the related property code once this becomes possible. */
+ ZEND_ASSERT(error_prop);
+ zend_type_error(
+ "Cannot %s a reference held by property %s::$%s of type %sint past its %simal value",
+ inc ? "increment" : "decrement",
+ ZSTR_VAL(error_prop->ce->name),
+ zend_get_unmangled_property_name(error_prop->name),
+ ZEND_TYPE_ALLOW_NULL(error_prop->type) ? "?" : "",
+ inc ? "max" : "min");
+}
+
+static void ZEND_FASTCALL zend_jit_pre_inc_typed_ref(zval *var_ptr, zend_reference *ref, zval *ret)
+{
+ zval tmp;
+
+ ZVAL_COPY(&tmp, var_ptr);
+
+ increment_function(var_ptr);
+
+ if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
+ zend_jit_throw_incdec_ref_error(ref, 1);
+ ZVAL_COPY_VALUE(var_ptr, &tmp);
+ } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
+ zval_ptr_dtor(var_ptr);
+ ZVAL_COPY_VALUE(var_ptr, &tmp);
+ } else {
+ zval_ptr_dtor(&tmp);
+ }
+ if (ret) {
+ ZVAL_COPY(ret, var_ptr);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_pre_dec_typed_ref(zval *var_ptr, zend_reference *ref, zval *ret)
+{
+ zval tmp;
+
+ ZVAL_COPY(&tmp, var_ptr);
+
+ decrement_function(var_ptr);
+
+ if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE(tmp) == IS_LONG) {
+ zend_jit_throw_incdec_ref_error(ref, 0);
+ ZVAL_COPY_VALUE(var_ptr, &tmp);
+ } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
+ zval_ptr_dtor(var_ptr);
+ ZVAL_COPY_VALUE(var_ptr, &tmp);
+ } else {
+ zval_ptr_dtor(&tmp);
+ }
+ if (ret) {
+ ZVAL_COPY(ret, var_ptr);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_post_inc_typed_ref(zval *var_ptr, zend_reference *ref, zval *ret)
+{
+ ZVAL_COPY(ret, var_ptr);
+
+ increment_function(var_ptr);
+
+ if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(ret) == IS_LONG) {
+ zend_jit_throw_incdec_ref_error(ref, 1);
+ ZVAL_COPY_VALUE(var_ptr, ret);
+ } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
+ zval_ptr_dtor(var_ptr);
+ ZVAL_COPY_VALUE(var_ptr, ret);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_post_dec_typed_ref(zval *var_ptr, zend_reference *ref, zval *ret)
+{
+ ZVAL_COPY(ret, var_ptr);
+
+ decrement_function(var_ptr);
+
+ if (UNEXPECTED(Z_TYPE_P(var_ptr) == IS_DOUBLE) && Z_TYPE_P(ret) == IS_LONG) {
+ zend_jit_throw_incdec_ref_error(ref, 0);
+ ZVAL_COPY_VALUE(var_ptr, ret);
+ } else if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, var_ptr, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
+ zval_ptr_dtor(var_ptr);
+ ZVAL_COPY_VALUE(var_ptr, ret);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_assign_op_to_typed_ref(zend_reference *ref, zval *val, binary_op_type binary_op)
+{
+ zval z_copy;
+
+ binary_op(&z_copy, &ref->val, val);
+ if (EXPECTED(zend_verify_ref_assignable_zval(ref, &z_copy, ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data))))) {
+ zval_ptr_dtor(&ref->val);
+ ZVAL_COPY_VALUE(&ref->val, &z_copy);
+ } else {
+ zval_ptr_dtor(&z_copy);
+ }
+}
+
+static void ZEND_FASTCALL zend_jit_only_vars_by_reference(zval *arg)
+{
+ ZVAL_NEW_REF(arg, arg);
+ zend_error(E_NOTICE, "Only variables should be passed by reference");
+}
+
+static void ZEND_FASTCALL zend_jit_invalid_array_access(zval *container)
+{
+ const char *type = Z_ISUNDEF_P(container) ? "null" : zend_zval_type_name(container);
+ zend_error(E_WARNING, "Trying to access array offset on value of type %s", type);
+}
+
+static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref(zval *ref) {
+ zval *val = Z_REFVAL_P(ref);
+ if (Z_TYPE_P(val) <= IS_FALSE) {
+ if (ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(ref))
+ && !zend_verify_ref_array_assignable(Z_REF_P(ref))) {
+ return NULL;
+ }
+ ZVAL_ARR(val, zend_new_array(8));
+ }
+ return val;
+}
+
+static void ZEND_FASTCALL zend_jit_pre_inc(zval *var_ptr, zval *ret)
+{
+ increment_function(var_ptr);
+ ZVAL_COPY(ret, var_ptr);
+}
+
+static void ZEND_FASTCALL zend_jit_pre_dec(zval *var_ptr, zval *ret)
+{
+ decrement_function(var_ptr);
+ ZVAL_COPY(ret, var_ptr);
+}
diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h
new file mode 100644
index 0000000000..f327fd5128
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_internal.h
@@ -0,0 +1,119 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ | Xinchen Hui <laruence@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_JIT_INTERNAL_H
+#define ZEND_JIT_INTERNAL_H
+
+/* Profiler */
+extern zend_ulong zend_jit_profile_counter;
+extern int zend_jit_profile_counter_rid;
+
+#define ZEND_COUNTER_INFO(op_array) \
+ ZEND_OP_ARRAY_EXTENSION(op_array, zend_jit_profile_counter_rid)
+
+/* Hot Counters */
+
+#define ZEND_HOT_COUNTERS_COUNT 128
+
+extern int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT];
+
+void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline);
+
+typedef struct _zend_jit_op_array_extension {
+ int16_t *counter;
+ const void *orig_handlers[1];
+} zend_jit_op_array_extension;
+
+static zend_always_inline zend_long zend_jit_op_array_hash(const zend_op_array *op_array)
+{
+ uintptr_t x;
+
+ x = (uintptr_t)op_array->opcodes >> 3;
+#if SIZEOF_SIZE_T == 4
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = ((x >> 16) ^ x) * 0x45d9f3b;
+ x = (x >> 16) ^ x;
+#elif SIZEOF_SIZE_T == 8
+ x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
+ x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
+ x = x ^ (x >> 31);
+#endif
+ return x;
+}
+
+extern const zend_op *zend_jit_halt_op;
+
+#ifdef HAVE_GCC_GLOBAL_REGS
+# define EXECUTE_DATA_D void
+# define EXECUTE_DATA_C
+# define EXECUTE_DATA_DC
+# define EXECUTE_DATA_CC
+# define OPLINE_D void
+# define OPLINE_C
+# define OPLINE_DC
+# define OPLINE_CC
+# define ZEND_OPCODE_HANDLER_RET void
+# define ZEND_OPCODE_HANDLER_ARGS EXECUTE_DATA_D
+# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU
+# define ZEND_OPCODE_HANDLER_ARGS_DC
+# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC
+# define ZEND_OPCODE_RETURN() return
+# define ZEND_OPCODE_TAIL_CALL(handler) do { \
+ handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); \
+ return; \
+ } while(0)
+#else
+# define EXECUTE_DATA_D zend_execute_data* execute_data
+# define EXECUTE_DATA_C execute_data
+# define EXECUTE_DATA_DC , EXECUTE_DATA_D
+# define EXECUTE_DATA_CC , EXECUTE_DATA_C
+# define OPLINE_D const zend_op* opline
+# define OPLINE_C opline
+# define OPLINE_DC , OPLINE_D
+# define OPLINE_CC , OPLINE_C
+# define ZEND_OPCODE_HANDLER_RET int
+# define ZEND_OPCODE_HANDLER_ARGS EXECUTE_DATA_D
+# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU EXECUTE_DATA_C
+# define ZEND_OPCODE_HANDLER_ARGS_DC EXECUTE_DATA_DC
+# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC EXECUTE_DATA_CC
+# define ZEND_OPCODE_RETURN() return 0
+# define ZEND_OPCODE_TAIL_CALL(handler) do { \
+ return handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); \
+ } while(0)
+#endif
+
+/* VM handlers */
+typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *zend_vm_opcode_handler_t)(ZEND_OPCODE_HANDLER_ARGS);
+
+/* VM helpers */
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC);
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t call_info EXECUTE_DATA_DC);
+
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS);
+
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_HANDLER_ARGS);
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS);
+
+void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D);
+void ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D);
+
+void ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags);
+int ZEND_FASTCALL zend_jit_check_constant(const zval *key);
+
+#endif /* ZEND_JIT_INTERNAL_H */
diff --git a/ext/opcache/jit/zend_jit_oprofile.c b/ext/opcache/jit/zend_jit_oprofile.c
new file mode 100644
index 0000000000..50dd027279
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_oprofile.c
@@ -0,0 +1,50 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#define HAVE_OPROFILE 1
+
+#include <opagent.h>
+
+static op_agent_t op_agent = NULL;
+
+static void zend_jit_oprofile_register(const char *name,
+ const void *start,
+ size_t size)
+{
+ if (op_agent) {
+ op_write_native_code(op_agent, name, (uint64_t)(zend_uintptr_t)start, start, size);
+ }
+}
+
+static int zend_jit_oprofile_startup(void)
+{
+ op_agent = op_open_agent();
+ if (!op_agent) {
+ fprintf(stderr, "OpAgent initialization failed [%d]!\n", errno);
+ return 0;
+ }
+ return 1;
+}
+
+static void zend_jit_oprofile_shutdown(void)
+{
+ if (op_agent) {
+//??? sleep(60);
+ op_close_agent(op_agent);
+ }
+}
diff --git a/ext/opcache/jit/zend_jit_perf_dump.c b/ext/opcache/jit/zend_jit_perf_dump.c
new file mode 100644
index 0000000000..94b1e4b859
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_perf_dump.c
@@ -0,0 +1,246 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#define HAVE_PERFTOOLS 1
+
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+
+#if defined(__darwin__)
+# include <pthread.h>
+#elif defined(__FreeBSD__)
+# include <sys/thr.h>
+# include <sys/sysctl.h>
+#elif defined(__NetBSD__)
+# include <lwp.h>
+#endif
+
+#include "zend_elf.h"
+
+/*
+ * 1) Profile using perf-<pid>.map
+ *
+ * perf record php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x10 bench.php
+ * perf report
+ *
+ * 2) Profile using jit-<pid>.dump
+ *
+ * perf record -k 1 php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x20 bench.php
+ * perf inject -j -i perf.data -o perf.data.jitted
+ * perf report -i perf.data.jitted
+ *
+ */
+
+
+#define ZEND_PERF_JITDUMP_HEADER_MAGIC 0x4A695444
+#define ZEND_PERF_JITDUMP_HEADER_VERSION 1
+
+#define ZEND_PERF_JITDUMP_RECORD_LOAD 0
+#define ZEND_PERF_JITDUMP_RECORD_MOVE 1
+#define ZEND_PERF_JITDUMP_RECORD_DEBUG_INFO 2
+#define ZEND_PERF_JITDUMP_RECORD_CLOSE 3
+#define ZEND_PERF_JITDUMP_UNWINDING_UNFO 4
+
+#define ALIGN8(size) (((size) + 7) & ~7)
+#define PADDING8(size) (ALIGN8(size) - (size))
+
+typedef struct zend_perf_jitdump_header {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t size;
+ uint32_t elf_mach_target;
+ uint32_t reserved;
+ uint32_t process_id;
+ uint64_t time_stamp;
+ uint64_t flags;
+} zend_perf_jitdump_header;
+
+typedef struct _zend_perf_jitdump_record {
+ uint32_t event;
+ uint32_t size;
+ uint64_t time_stamp;
+} zend_perf_jitdump_record;
+
+typedef struct _zend_perf_jitdump_load_record {
+ zend_perf_jitdump_record hdr;
+ uint32_t process_id;
+ uint32_t thread_id;
+ uint64_t vma;
+ uint64_t code_address;
+ uint64_t code_size;
+ uint64_t code_id;
+} zend_perf_jitdump_load_record;
+
+static int jitdump_fd = -1;
+static void *jitdump_mem = MAP_FAILED;
+
+static uint64_t zend_perf_timestamp(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
+ return 0;
+ }
+ return ((uint64_t)ts.tv_sec * 1000000000) + ts.tv_nsec;
+}
+
+static void zend_jit_perf_jitdump_open(void)
+{
+ char filename[64];
+ int fd, ret;
+ zend_elf_header elf_hdr;
+ zend_perf_jitdump_header jit_hdr;
+
+ sprintf(filename, "/tmp/jit-%d.dump", getpid());
+ if (!zend_perf_timestamp()) {
+ return;
+ }
+
+#if defined(__linux__)
+ fd = open("/proc/self/exe", O_RDONLY);
+#elif defined(__NetBSD__)
+ fd = open("/proc/curproc/exe", O_RDONLY);
+#elif defined(__FreeBSD__)
+ char path[PATH_MAX];
+ size_t pathlen = sizeof(path);
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ if (sysctl(mib, 4, path, &pathlen, NULL, 0) == -1) {
+ return;
+ }
+ fd = open(path, O_RDONLY);
+#else
+ fd = -1;
+#endif
+ if (fd < 0) {
+ return;
+ }
+
+ ret = read(fd, &elf_hdr, sizeof(elf_hdr));
+ close(fd);
+
+ if (ret != sizeof(elf_hdr) ||
+ elf_hdr.emagic[0] != 0x7f ||
+ elf_hdr.emagic[1] != 'E' ||
+ elf_hdr.emagic[2] != 'L' ||
+ elf_hdr.emagic[3] != 'F') {
+ return;
+ }
+
+ jitdump_fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0666);
+ if (jitdump_fd < 0) {
+ return;
+ }
+
+ jitdump_mem = mmap(NULL,
+ sysconf(_SC_PAGESIZE),
+ PROT_READ|PROT_EXEC,
+ MAP_PRIVATE, jitdump_fd, 0);
+
+ if (jitdump_mem == MAP_FAILED) {
+ close(jitdump_fd);
+ jitdump_fd = -1;
+ return;
+ }
+
+ memset(&jit_hdr, 0, sizeof(jit_hdr));
+ jit_hdr.magic = ZEND_PERF_JITDUMP_HEADER_MAGIC;
+ jit_hdr.version = ZEND_PERF_JITDUMP_HEADER_VERSION;
+ jit_hdr.size = sizeof(jit_hdr);
+ jit_hdr.elf_mach_target = elf_hdr.machine;
+ jit_hdr.process_id = getpid();
+ jit_hdr.time_stamp = zend_perf_timestamp();
+ jit_hdr.flags = 0;
+ zend_quiet_write(jitdump_fd, &jit_hdr, sizeof(jit_hdr));
+}
+
+static void zend_jit_perf_jitdump_close(void)
+{
+ if (jitdump_fd >= 0) {
+ zend_perf_jitdump_record rec;
+
+ rec.event = ZEND_PERF_JITDUMP_RECORD_CLOSE;
+ rec.size = sizeof(rec);
+ rec.time_stamp = zend_perf_timestamp();
+ zend_quiet_write(jitdump_fd, &rec, sizeof(rec));
+ close(jitdump_fd);
+
+ if (jitdump_mem != MAP_FAILED) {
+ munmap(jitdump_mem, sysconf(_SC_PAGESIZE));
+ }
+ }
+}
+
+static void zend_jit_perf_jitdump_register(const char *name, void *start, size_t size)
+{
+ if (jitdump_fd >= 0) {
+ static uint64_t id = 1;
+ zend_perf_jitdump_load_record rec;
+ size_t len = strlen(name);
+ uint32_t thread_id = 0;
+#if defined(__linux__)
+ thread_id = syscall(SYS_gettid);
+#elif defined(__darwin__)
+ uint64_t thread_id_u64;
+ pthread_threadid_np(NULL, &thread_id_u64);
+ thread_id = (uint32_t) thread_id_u64;
+#elif defined(__FreeBSD__)
+ long tid;
+ thr_self(&tid);
+ thread_id = (uint32_t)tid;
+#elif defined(__OpenBSD__)
+ thread_id = getthrid();
+#elif defined(__NetBSD__)
+ thread_id = _lwp_self();
+#endif
+
+ memset(&rec, 0, sizeof(rec));
+ rec.hdr.event = ZEND_PERF_JITDUMP_RECORD_LOAD;
+ rec.hdr.size = sizeof(rec) + len + 1 + size;
+ rec.hdr.time_stamp = zend_perf_timestamp();
+ rec.process_id = getpid();
+ rec.thread_id = thread_id;
+ rec.vma = (uint64_t)(uintptr_t)start;
+ rec.code_address = (uint64_t)(uintptr_t)start;
+ rec.code_size = (uint64_t)size;
+ rec.code_id = id++;
+
+ zend_quiet_write(jitdump_fd, &rec, sizeof(rec));
+ zend_quiet_write(jitdump_fd, name, len + 1);
+ zend_quiet_write(jitdump_fd, start, size);
+ }
+}
+
+static void zend_jit_perf_map_register(const char *name, void *start, size_t size)
+{
+ static FILE *fp = NULL;
+
+ if (!fp) {
+ char filename[64];
+
+ sprintf(filename, "/tmp/perf-%d.map", getpid());
+ fp = fopen(filename, "w");
+ if (!fp) {
+ return;
+ }
+ setlinebuf(fp);
+ }
+ fprintf(fp, "%zx %zx %s\n", (size_t)(uintptr_t)start, size, name);
+}
diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c
new file mode 100644
index 0000000000..9862fd1b42
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_vm_helpers.c
@@ -0,0 +1,268 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ | Xinchen Hui <laruence@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "Zend/zend_execute.h"
+#include "Zend/zend_exceptions.h"
+#include "Zend/zend_vm.h"
+#include "Zend/zend_closures.h"
+#include "Zend/zend_constants.h"
+#include "Zend/zend_API.h"
+
+#include <ZendAccelerator.h>
+#include "Optimizer/zend_func_info.h"
+#include "zend_jit.h"
+#include "zend_jit_internal.h"
+
+#ifdef HAVE_GCC_GLOBAL_REGS
+# pragma GCC diagnostic ignored "-Wvolatile-register-var"
+# if defined(__x86_64__)
+register zend_execute_data* volatile execute_data __asm__("%r14");
+register const zend_op* volatile opline __asm__("%r15");
+# else
+register zend_execute_data* volatile execute_data __asm__("%esi");
+register const zend_op* volatile opline __asm__("%edi");
+# endif
+# pragma GCC diagnostic warning "-Wvolatile-register-var"
+#endif
+
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC)
+{
+ zend_execute_data *old_execute_data;
+
+ if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
+ zend_clean_and_cache_symbol_table(EX(symbol_table));
+ }
+
+ zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+ if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+ OBJ_RELEASE(Z_OBJ(execute_data->This));
+ } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
+ }
+
+ old_execute_data = execute_data;
+ execute_data = EX(prev_execute_data);
+ zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ const zend_op *old_opline = EX(opline);
+ zend_throw_exception_internal(NULL);
+ if (old_opline->result_type != IS_UNDEF) {
+ zval_ptr_dtor(EX_VAR(old_opline->result.var));
+ }
+#ifndef HAVE_GCC_GLOBAL_REGS
+ return 2; // ZEND_VM_LEAVE
+#endif
+ } else {
+ EX(opline)++;
+#ifdef HAVE_GCC_GLOBAL_REGS
+ opline = EX(opline);
+#else
+ return 2; // ZEND_VM_LEAVE
+#endif
+ }
+}
+
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t call_info EXECUTE_DATA_DC)
+{
+ if (UNEXPECTED(call_info & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) {
+ if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
+ zend_clean_and_cache_symbol_table(EX(symbol_table));
+ }
+ zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+ }
+ if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
+ }
+ execute_data = EG(current_execute_data);
+#ifdef HAVE_GCC_GLOBAL_REGS
+ opline = zend_jit_halt_op;
+#else
+ return -1; // ZEND_VM_RETURN
+#endif
+}
+
+void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D)
+{
+ zend_op_array *op_array = &EX(func)->op_array;
+
+ if (EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
+ uint32_t first_extra_arg = op_array->num_args;
+ uint32_t num_args = EX_NUM_ARGS();
+ zval *end, *src, *dst;
+ uint32_t type_flags = 0;
+
+ if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
+ /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
+#ifdef HAVE_GCC_GLOBAL_REGS
+ opline += first_extra_arg;
+#endif
+ }
+
+ /* move extra args into separate array after all CV and TMP vars */
+ end = EX_VAR_NUM(first_extra_arg - 1);
+ src = end + (num_args - first_extra_arg);
+ dst = src + (op_array->last_var + op_array->T - first_extra_arg);
+ if (EXPECTED(src != dst)) {
+ do {
+ type_flags |= Z_TYPE_INFO_P(src);
+ ZVAL_COPY_VALUE(dst, src);
+ ZVAL_UNDEF(src);
+ src--;
+ dst--;
+ } while (src != end);
+ if (type_flags & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) {
+ ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
+ }
+ } else {
+ do {
+ if (Z_REFCOUNTED_P(src)) {
+ ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_FREE_EXTRA_ARGS);
+ break;
+ }
+ src--;
+ } while (src != end);
+ }
+ }
+}
+
+void ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D)
+{
+ zend_execute_data *call = (zend_execute_data *) opline;
+ zend_function *fbc = call->func;
+ zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
+ fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "",
+ fbc->common.scope ? "::" : "",
+ ZSTR_VAL(fbc->common.function_name));
+ if (EG(exception)) {
+#ifndef HAVE_GCC_GLOBAL_REGS
+ zend_execute_data *execute_data = EG(current_execute_data);
+#endif
+ const zend_op *opline = EG(opline_before_exception);
+ if (RETURN_VALUE_USED(opline)) {
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ }
+
+ zend_vm_stack_free_args(call);
+
+ if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
+ OBJ_RELEASE(Z_OBJ(call->This));
+ }
+
+ zend_vm_stack_free_call_frame(call);
+ }
+}
+
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_op_array *op_array = (zend_op_array*)EX(func);
+ zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)ZEND_FUNC_INFO(op_array);
+ uintptr_t counter = (uintptr_t)ZEND_COUNTER_INFO(op_array);
+
+ ZEND_COUNTER_INFO(op_array) = (void*)(counter + 1);
+ ++zend_jit_profile_counter;
+ ZEND_OPCODE_TAIL_CALL(handler);
+}
+
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_jit_op_array_extension *jit_extension =
+ (zend_jit_op_array_extension*)ZEND_FUNC_INFO(&EX(func)->op_array);
+#ifndef HAVE_GCC_GLOBAL_REGS
+ const zend_op *opline = EX(opline);
+#endif
+
+ *(jit_extension->counter) -= ZEND_JIT_HOT_FUNC_COST;
+
+ if (UNEXPECTED(*(jit_extension->counter) <= 0)) {
+ zend_jit_hot_func(execute_data, opline);
+ ZEND_OPCODE_RETURN();
+ } else {
+ zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)jit_extension->orig_handlers[opline - EX(func)->op_array.opcodes];
+ ZEND_OPCODE_TAIL_CALL(handler);
+ }
+}
+
+ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
+{
+ zend_jit_op_array_extension *jit_extension =
+ (zend_jit_op_array_extension*)ZEND_FUNC_INFO(&EX(func)->op_array);
+#ifndef HAVE_GCC_GLOBAL_REGS
+ const zend_op *opline = EX(opline);
+#endif
+
+ *(jit_extension->counter) -= ZEND_JIT_HOT_LOOP_COST;
+
+ if (UNEXPECTED(*(jit_extension->counter) <= 0)) {
+ zend_jit_hot_func(execute_data, opline);
+ ZEND_OPCODE_RETURN();
+ } else {
+ zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)jit_extension->orig_handlers[opline - EX(func)->op_array.opcodes];
+ ZEND_OPCODE_TAIL_CALL(handler);
+ }
+}
+
+static zend_always_inline int _zend_quick_get_constant(
+ const zval *key, uint32_t flags, int check_defined_only)
+{
+#ifndef HAVE_GCC_GLOBAL_REGS
+ zend_execute_data *execute_data = EG(current_execute_data);
+#endif
+ const zend_op *opline = EX(opline);
+ zval *zv;
+ zend_constant *c = NULL;
+
+ /* null/true/false are resolved during compilation, so don't check for them here. */
+ zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+ if (zv) {
+ c = (zend_constant*)Z_PTR_P(zv);
+ } else if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
+ key++;
+ zv = zend_hash_find_ex(EG(zend_constants), Z_STR_P(key), 1);
+ if (zv) {
+ c = (zend_constant*)Z_PTR_P(zv);
+ }
+ }
+
+ if (!c) {
+ if (!check_defined_only) {
+ zend_throw_error(NULL, "Undefined constant '%s'", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
+ ZVAL_UNDEF(EX_VAR(opline->result.var));
+ }
+ CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants))));
+ return FAILURE;
+ }
+
+ if (!check_defined_only) {
+ ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value);
+ }
+
+ CACHE_PTR(opline->extended_value, c);
+ return SUCCESS;
+}
+
+void ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags)
+{
+ _zend_quick_get_constant(key, flags, 0);
+}
+
+int ZEND_FASTCALL zend_jit_check_constant(const zval *key)
+{
+ return _zend_quick_get_constant(key, 0, 1);
+}
diff --git a/ext/opcache/jit/zend_jit_vtune.c b/ext/opcache/jit/zend_jit_vtune.c
new file mode 100644
index 0000000000..877afa8606
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_vtune.c
@@ -0,0 +1,42 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#define HAVE_VTUNE 1
+
+#include "jit/vtune/jitprofiling.h"
+#include "jit/vtune/jitprofiling.c"
+
+static void zend_jit_vtune_register(const char *name,
+ const void *start,
+ size_t size)
+{
+ iJIT_Method_Load jmethod = {0};
+
+ if (iJIT_IsProfilingActive() != iJIT_SAMPLING_ON) {
+ return;
+ }
+
+ jmethod.method_id = iJIT_GetNewMethodID();
+ jmethod.method_name = (char*)name;
+ jmethod.class_file_name = NULL;
+ jmethod.source_file_name = NULL;
+ jmethod.method_load_address = (void*)start;
+ jmethod.method_size = size;
+
+ iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod);
+}
diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc
new file mode 100644
index 0000000000..3b6e3b26f5
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_x86.dasc
@@ -0,0 +1,9827 @@
+/*
+ * +----------------------------------------------------------------------+
+ * | Zend JIT |
+ * +----------------------------------------------------------------------+
+ * | Copyright (c) The PHP Group |
+ * +----------------------------------------------------------------------+
+ * | This source file is subject to version 3.01 of the PHP license, |
+ * | that is bundled with this package in the file LICENSE, and is |
+ * | available through the world-wide-web at the following url: |
+ * | http://www.php.net/license/3_01.txt |
+ * | If you did not receive a copy of the PHP license and are unable to |
+ * | obtain it through the world-wide-web, please send a note to |
+ * | license@php.net so we can mail you a copy immediately. |
+ * +----------------------------------------------------------------------+
+ * | Authors: Dmitry Stogov <dmitry@php.net> |
+ * | Xinchen Hui <laruence@php.net> |
+ * +----------------------------------------------------------------------+
+ */
+
+|.if X64
+ |.arch x64
+|.else
+ |.arch x86
+|.endif
+
+|.if X64WIN
+ |.define FP, r14
+ |.define IP, r15
+ |.define IPl, r15d
+ |.define RX, r15 // the same as VM IP reused as a general purpos reg
+ |.define CARG1, rcx // x64/POSIX C call arguments.
+ |.define CARG2, rdx
+ |.define CARG3, r8
+ |.define CARG4, r9
+ |.define CARG1d, ecx
+ |.define CARG2d, edx
+ |.define CARG3d, r8d
+ |.define CARG4d, r9d
+ |.define FCARG1a, CARG1 // Simulate x86 fastcall.
+ |.define FCARG2a, CARG2
+ |.define FCARG1d, CARG1d
+ |.define FCARG2d, CARG2d
+ |.define SPAD, 0x08 // padding for CPU stack alignment
+ |.define NR_SPAD, 0x58 // padding for CPU stack alignment
+ |.define T3, [r4+0x50] // Used to store old value of IP
+ |.define T2, [r4+0x48] // Used to store old value of FP
+ |.define T1, [r4+0x40]
+ |.define A6, [r4+0x28] // preallocated slot for 6-th argument
+ |.define A5, [r4+0x20] // preallocated slot for 5-th argument
+|.elif X64
+ |.define FP, r14
+ |.define IP, r15
+ |.define IPl, r15d
+ |.define RX, r15 // the same as VM IP reused as a general purpos reg
+ |.define CARG1, rdi // x64/POSIX C call arguments.
+ |.define CARG2, rsi
+ |.define CARG3, rdx
+ |.define CARG4, rcx
+ |.define CARG5, r8
+ |.define CARG6, r9
+ |.define CARG1d, edi
+ |.define CARG2d, esi
+ |.define CARG3d, edx
+ |.define CARG4d, ecx
+ |.define CARG5d, r8d
+ |.define CARG6d, r9d
+ |.define FCARG1a, CARG1 // Simulate x86 fastcall.
+ |.define FCARG2a, CARG2
+ |.define FCARG1d, CARG1d
+ |.define FCARG2d, CARG2d
+ |.define SPAD, 0x08 // padding for CPU stack alignment
+ |.define NR_SPAD, 0x18 // padding for CPU stack alignment
+ |.define T3, [r4+0x10] // Used to store old value of IP (CALL VM only)
+ |.define T2, [r4+0x08] // Used to store old value of FP (CALL VM only)
+ |.define T1, [r4]
+|.else
+ |.define FP, esi
+ |.define IP, edi
+ |.define IPl, edi
+ |.define RX, edi // the same as VM IP reused as a general purpos reg
+ |.define FCARG1a, ecx // x86 fastcall arguments.
+ |.define FCARG2a, edx
+ |.define FCARG1d, ecx
+ |.define FCARG2d, edx
+ |.define SPAD, 12 // padding for CPU stack alignment
+ |.define NR_SPAD, 12 // padding for CPU stack alignment
+ |.define T3, [r4+0x10] // Used to store old value of IP (CALL VM only)
+ |.define T2, [r4+0x08] // Used to store old value of FP (CALL VM only)
+ |.define T1, [r4]
+|.endif
+
+|.define HYBRID_SPAD, 16 // padding for stack alignment
+
+/* According to x86 and x86_64 ABI, CPU stack has to be 16 byte aligned to
+ * guarantee proper alignment of 128-bit SSE data allocated on stack.
+ * With broken alignment any execution of SSE code, including calls to
+ * memcpy() and others, may lead to crash.
+ */
+
+#include "Zend/zend_cpuinfo.h"
+#include "jit/zend_jit_x86.h"
+
+/* The generated code may contain tautological comparisons, ignore them. */
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wtautological-compare"
+#endif
+
+const char* zend_reg_name[] = {
+#if defined(__x86_64__) || defined(_M_X64)
+ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
+#else
+ "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
+#endif
+};
+
+#ifdef HAVE_GCC_GLOBAL_REGS
+# define GCC_GLOBAL_REGS 1
+#else
+# define GCC_GLOBAL_REGS 0
+#endif
+
+static uint32_t zend_jit_x86_flags = 0;
+
+#if ZTS
+static size_t tsrm_ls_cache_tcb_offset = 0;
+static size_t tsrm_tls_index;
+static size_t tsrm_tls_offset;
+#endif
+
+/* By default avoid JITing inline handlers if it does not seem profitable due to lack of
+ * type information. Disabling this option allows testing some JIT handlers in the
+ * presence of try/catch blocks, which prevent SSA construction. */
+#ifndef PROFITABILITY_CHECKS
+# define PROFITABILITY_CHECKS 1
+#endif
+
+|.type EX, zend_execute_data, FP
+|.type OP, zend_op
+|.type ZVAL, zval
+
+|.actionlist dasm_actions
+
+|.globals zend_lb
+static void* dasm_labels[zend_lb_MAX];
+
+|.section code, cold_code
+
+#define IS_32BIT(addr) (((uintptr_t)(addr)) <= 0xffffffff)
+
+#define IS_SIGNED_32BIT(val) ((((intptr_t)(val)) <= 0x7fffffff) && (((intptr_t)(val)) >= (-2147483647 - 1)))
+
+#define BP_JIT_IS 6
+
+|.macro LOAD_ADDR, reg, addr
+| .if X64
+|| if (IS_32BIT(addr)) {
+| mov reg, ((ptrdiff_t)addr) // 0x48 0xc7 0xc0 <imm-32-bit>
+|| } else {
+| mov64 reg, ((ptrdiff_t)addr) // 0x48 0xb8 <imm-64-bit>
+|| }
+| .else
+| mov reg, ((ptrdiff_t)addr)
+| .endif
+|.endmacro
+
+|.macro LOAD_TSRM_CACHE, reg
+| .if X64WIN
+| gs
+| mov reg, aword [0x58]
+| mov reg, aword [reg + tsrm_tls_index]
+| mov reg, aword [reg + tsrm_tls_offset]
+| .elif WIN
+| fs
+| mov reg, aword [0x2c]
+| mov reg, aword [reg + tsrm_tls_index]
+| mov reg, aword [reg + tsrm_tls_offset]
+| .elif X64APPLE
+| gs
+|| if (tsrm_ls_cache_tcb_offset) {
+| mov reg, aword [tsrm_ls_cache_tcb_offset]
+|| } else {
+| mov reg, aword [tsrm_tls_index]
+| mov reg, aword [reg + tsrm_tls_offset]
+|| }
+| .elif X64
+| fs
+|| if (tsrm_ls_cache_tcb_offset) {
+| mov reg, aword [tsrm_ls_cache_tcb_offset]
+|| } else {
+| mov reg, [0x8]
+| mov reg, aword [reg + tsrm_tls_index]
+| mov reg, aword [reg + tsrm_tls_offset]
+|| }
+| .else
+| gs
+|| if (tsrm_ls_cache_tcb_offset) {
+| mov reg, aword [tsrm_ls_cache_tcb_offset]
+|| } else {
+| mov reg, [0x4]
+| mov reg, aword [reg + tsrm_tls_index]
+| mov reg, aword [reg + tsrm_tls_offset]
+|| }
+| .endif
+|.endmacro
+
+|.macro LOAD_ADDR_ZTS, reg, struct, field
+| .if ZTS
+| LOAD_TSRM_CACHE reg
+| lea reg, aword [reg + (struct.._offset + offsetof(zend_..struct, field))]
+| .else
+| LOAD_ADDR reg, &struct.field
+| .endif
+|.endmacro
+
+|.macro SAVE_OPLINE
+|| if (GCC_GLOBAL_REGS) {
+| mov aword EX->opline, IP
+|| }
+|.endmacro
+
+|.macro LOAD_OPLINE
+|| if (GCC_GLOBAL_REGS) {
+| mov IP, aword EX->opline
+|| }
+|.endmacro
+
+|.macro LOAD_IP_ADDR, addr
+|| if (GCC_GLOBAL_REGS) {
+| LOAD_ADDR IP, addr
+|| } else {
+| LOAD_ADDR RX, addr
+| mov aword EX->opline, RX
+|| }
+|.endmacro
+
+|.macro LOAD_IP_ADDR_ZTS, struct, field
+| .if ZTS
+|| if (GCC_GLOBAL_REGS) {
+| LOAD_TSRM_CACHE IP
+| mov IP, aword [IP + (struct.._offset + offsetof(zend_..struct, field))]
+|| } else {
+| LOAD_TSRM_CACHE RX
+| lea RX, aword [RX + (struct.._offset + offsetof(zend_..struct, field))]
+| mov aword EX->opline, RX
+|| }
+| .else
+| LOAD_IP_ADDR &struct.field
+| .endif
+|.endmacro
+
+|.macro GET_IP, reg
+|| if (GCC_GLOBAL_REGS) {
+| mov reg, IP
+|| } else {
+| mov reg, aword EX->opline
+|| }
+|.endmacro
+
+|.macro ADD_IP, val
+|| if (GCC_GLOBAL_REGS) {
+| add IP, val
+|| } else {
+| add aword EX->opline, val
+|| }
+|.endmacro
+
+|.macro JMP_IP
+|| if (GCC_GLOBAL_REGS) {
+| jmp aword [IP]
+|| } else {
+| mov r0, aword EX:FCARG1a->opline
+| jmp aword [r0]
+|| }
+|.endmacro
+
+/* In 64-bit build we compare only low 32-bits.
+ * x86_64 cmp instruction doesn't support immediate 64-bit operand, and full
+ * comparison would require additinal load of 64-bit address into register.
+ * This is not a problem at all, while JIT buffer size is less than 4GB.
+ */
+|.macro CMP_IP, addr
+|| if (GCC_GLOBAL_REGS) {
+| cmp IPl, addr
+|| } else {
+| cmp dword EX->opline, addr
+|| }
+|.endmacro
+
+|.macro ADDR_OP1, addr_ins, addr, tmp_reg
+| .if X64
+|| if (IS_32BIT(addr)) {
+| addr_ins ((ptrdiff_t)addr)
+|| } else {
+| mov64 tmp_reg, ((ptrdiff_t)addr)
+| addr_ins tmp_reg
+|| }
+| .else
+| addr_ins ((ptrdiff_t)addr)
+| .endif
+|.endmacro
+
+|.macro ADDR_OP2_2, addr_ins, op1, addr, tmp_reg
+| .if X64
+|| if (IS_32BIT(addr)) {
+| addr_ins op1, ((ptrdiff_t)addr)
+|| } else {
+| mov64 tmp_reg, ((ptrdiff_t)addr)
+| addr_ins op1, tmp_reg
+|| }
+| .else
+| addr_ins op1, ((ptrdiff_t)addr)
+| .endif
+|.endmacro
+
+|.macro PUSH_ADDR, addr, tmp_reg
+| ADDR_OP1 push, addr, tmp_reg
+|.endmacro
+
+|.macro PUSH_ADDR_ZTS, struct, field, tmp_reg
+| .if ZTS
+| LOAD_TSRM_CACHE tmp_reg
+| lea tmp_reg, aword [tmp_reg + (struct.._offset + offsetof(zend_..struct, field))]
+| push tmp_reg
+| .else
+| ADDR_OP1 push, &struct.field, tmp_reg
+| .endif
+|.endmacro
+
+|.macro MEM_OP1, mem_ins, prefix, addr, tmp_reg
+| .if X64
+|| if (IS_32BIT(addr)) {
+| mem_ins prefix [addr]
+|| } else {
+| mov64 tmp_reg, ((ptrdiff_t)addr)
+| mem_ins prefix [tmp_reg]
+|| }
+| .else
+| mem_ins prefix [addr]
+| .endif
+|.endmacro
+
+|.macro MEM_OP2_1, mem_ins, prefix, addr, op2, tmp_reg
+| .if X64
+|| if (IS_32BIT(addr)) {
+| mem_ins prefix [addr], op2
+|| } else {
+| mov64 tmp_reg, ((ptrdiff_t)addr)
+| mem_ins prefix [tmp_reg], op2
+|| }
+| .else
+| mem_ins prefix [addr], op2
+| .endif
+|.endmacro
+
+|.macro MEM_OP2_2, mem_ins, op1, prefix, addr, tmp_reg
+| .if X64
+|| if (IS_32BIT(addr)) {
+| mem_ins op1, prefix [addr]
+|| } else {
+| mov64 tmp_reg, ((ptrdiff_t)addr)
+| mem_ins op1, prefix [tmp_reg]
+|| }
+| .else
+| mem_ins op1, prefix [addr]
+| .endif
+|.endmacro
+
+|.macro MEM_OP2_1_ZTS, mem_ins, prefix, struct, field, op2, tmp_reg
+| .if ZTS
+| LOAD_TSRM_CACHE tmp_reg
+| mem_ins prefix [tmp_reg + (struct.._offset + offsetof(zend_..struct, field))], op2
+| .else
+| MEM_OP2_1 mem_ins, prefix, &struct.field, op2, tmp_reg
+| .endif
+|.endmacro
+
+|.macro MEM_OP2_2_ZTS, mem_ins, op1, prefix, struct, field, tmp_reg
+| .if ZTS
+| LOAD_TSRM_CACHE tmp_reg
+| mem_ins op1, prefix [tmp_reg + (struct.._offset + offsetof(zend_..struct, field))]
+| .else
+| MEM_OP2_2 mem_ins, op1, prefix, &struct.field, tmp_reg
+| .endif
+|.endmacro
+
+|.macro MEM_OP3_3, mem_ins, op1, op2, prefix, addr, tmp_reg
+| .if X64
+|| if (IS_32BIT(addr)) {
+| mem_ins op1, op2, prefix [addr]
+|| } else {
+| mov64 tmp_reg, ((ptrdiff_t)addr)
+| mem_ins op1, op2, prefix [tmp_reg]
+|| }
+| .else
+| mem_ins op1, op2, prefix [addr]
+| .endif
+|.endmacro
+
+|.macro LOAD_BASE_ADDR, reg, base, offset
+|| if (offset) {
+| lea reg, qword [Ra(base)+offset]
+|| } else {
+| mov reg, Ra(base)
+|| }
+|.endmacro
+
+|.macro PUSH_BASE_ADDR, base, offset, tmp_reg
+|| if (offset) {
+| lea tmp_reg, qword [Ra(base)+offset]
+| push tmp_reg
+|| } else {
+| push Ra(base)
+|| }
+|.endmacro
+
+|.macro EXT_CALL, func, tmp_reg
+| .if X64
+|| if (IS_32BIT(dasm_end) && IS_32BIT(func)) {
+| call qword &func
+|| } else {
+| LOAD_ADDR tmp_reg, func
+| call tmp_reg
+|| }
+| .else
+| call dword &func
+| .endif
+|.endmacro
+
+|.macro EXT_JMP, func, tmp_reg
+| .if X64
+|| if (IS_32BIT(dasm_end) && IS_32BIT(func)) {
+| jmp qword &func
+|| } else {
+| LOAD_ADDR tmp_reg, func
+| jmp tmp_reg
+|| }
+| .else
+| jmp dword &func
+| .endif
+|.endmacro
+
+|.macro LOAD_ZVAL_ADDR, reg, addr
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| LOAD_ADDR reg, Z_ZV(addr)
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| LOAD_BASE_ADDR reg, Z_REG(addr), Z_OFFSET(addr)
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro PUSH_ZVAL_ADDR, addr, tmp_reg
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| PUSH_ADDR Z_ZV(addr), tmp_reg
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| PUSH_BASE_ADDR Z_REG(addr), Z_OFFSET(addr), tmp_reg
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro GET_Z_TYPE_INFO, reg, zv
+| mov reg, dword [zv+offsetof(zval,u1.type_info)]
+|.endmacro
+
+|.macro SET_Z_TYPE_INFO, zv, type
+| mov dword [zv+offsetof(zval,u1.type_info)], type
+|.endmacro
+
+|.macro GET_ZVAL_TYPE_INFO, reg, addr
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| mov reg, dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.type_info)]
+|.endmacro
+
+|.macro SET_ZVAL_TYPE_INFO, addr, type
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| mov dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval,u1.type_info)], type
+|.endmacro
+
+|.macro GET_Z_PTR, reg, zv
+| mov reg, aword [zv]
+|.endmacro
+
+|.macro SET_Z_PTR, zv, val
+| mov aword [zv], val
+|.endmacro
+
+|.macro GET_ZVAL_PTR, reg, addr
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| mov reg, aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|.endmacro
+
+|.macro SET_ZVAL_PTR, addr, val
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| mov aword [Ra(Z_REG(addr))+Z_OFFSET(addr)], val
+|.endmacro
+
+|.macro GET_ZVAL_W2, reg, addr
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| mov reg, dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+4]
+|.endmacro
+
+|.macro SET_ZVAL_W2, addr, val
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| mov dword [Ra(Z_REG(addr))+Z_OFFSET(addr)+4], val
+|.endmacro
+
+|.macro UNDEF_OPLINE_RESULT
+| mov r0, EX->opline
+|.if X64
+ | movsxd r0, dword OP:r0->result.var
+|.else
+ | mov r0, OP:r0->result.var
+|.endif
+| SET_Z_TYPE_INFO FP + r0, IS_UNDEF
+|.endmacro
+
+|.macro SSE_AVX_INS, sse_ins, avx_ins, op1, op2
+|| if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+| avx_ins op1, op2
+|| } else {
+| sse_ins op1, op2
+|| }
+|.endmacro
+
+|.macro SSE_OP, sse_ins, reg, addr
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| MEM_OP2_2 sse_ins, xmm(reg-ZREG_XMM0), qword, Z_ZV(addr), r0
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| sse_ins xmm(reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| } else if (Z_MODE(addr) == IS_REG) {
+| sse_ins xmm(reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro SSE_AVX_OP, sse_ins, avx_ins, reg, addr
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| .if X64
+|| if (IS_32BIT(Z_ZV(addr))) {
+| SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
+|| } else {
+| LOAD_ADDR r0, Z_ZV(addr)
+| SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [r0]
+|| }
+| .else
+| SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
+| .endif
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| } else if (Z_MODE(addr) == IS_REG) {
+| SSE_AVX_INS sse_ins, avx_ins, xmm(reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro SSE_GET_LONG, reg, lval
+|| if (lval == 0) {
+|| if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+| vxorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
+|| } else {
+| xorps xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0)
+|| }
+|| } else {
+|.if X64
+|| if (!IS_SIGNED_32BIT(lval)) {
+| mov64 r0, lval
+|| } else {
+| mov r0, lval
+|| }
+|.else
+| mov r0, lval
+|.endif
+|| if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+| vcvtsi2sd, xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), r0
+|| } else {
+| cvtsi2sd, xmm(reg-ZREG_XMM0), r0
+|| }
+|| }
+|.endmacro
+
+|.macro SSE_GET_ZVAL_LVAL, reg, addr
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| SSE_GET_LONG reg, Z_LVAL_P(Z_ZV(addr))
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+|| if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+| vcvtsi2sd xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| } else {
+| cvtsi2sd xmm(reg-ZREG_XMM0), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| }
+|| } else if (Z_MODE(addr) == IS_REG) {
+|| if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+| vcvtsi2sd xmm(reg-ZREG_XMM0), xmm(reg-ZREG_XMM0), Ra(Z_REG(addr))
+|| } else {
+| cvtsi2sd xmm(reg-ZREG_XMM0), Ra(Z_REG(addr))
+|| }
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro SSE_GET_ZVAL_DVAL, reg, addr
+|| if (Z_MODE(addr) != IS_REG || reg != Z_REG(addr)) {
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| .if X64
+|| if (IS_32BIT(Z_ZV(addr))) {
+| SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
+|| } else {
+| LOAD_ADDR r0, Z_ZV(addr)
+| SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [r0]
+|| }
+| .else
+| SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [Z_ZV(addr)]
+| .endif
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| SSE_AVX_INS movsd, vmovsd, xmm(reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| } else if (Z_MODE(addr) == IS_REG) {
+| SSE_AVX_INS movsd, vmovaps, xmm(reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|| }
+|.endmacro
+
+|.macro SSE_MATH, opcode, reg, addr
+|| switch (opcode) {
+|| case ZEND_ADD:
+| SSE_OP addsd, reg, addr
+|| break;
+|| case ZEND_SUB:
+| SSE_OP subsd, reg, addr
+|| break;
+|| case ZEND_MUL:
+| SSE_OP mulsd, reg, addr
+|| break;
+|| case ZEND_DIV:
+| SSE_OP divsd, reg, addr
+|| break;
+|| }
+|.endmacro
+
+|.macro SSE_MATH_REG, opcode, dst_reg, src_reg
+|| switch (opcode) {
+|| case ZEND_ADD:
+| addsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| case ZEND_SUB:
+| subsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| case ZEND_MUL:
+| mulsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| case ZEND_DIV:
+| divsd xmm(dst_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| }
+|.endmacro
+
+|.macro SSE_SET_ZVAL_DVAL, addr, reg
+|| if (Z_MODE(addr) == IS_REG) {
+|| if (reg != Z_REG(addr)) {
+| SSE_AVX_INS movsd, vmovaps, xmm(Z_REG(addr)-ZREG_XMM0), xmm(reg-ZREG_XMM0)
+|| }
+|| } else {
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| SSE_AVX_INS movsd, vmovsd, qword [Ra(Z_REG(addr))+Z_OFFSET(addr)], xmm(reg-ZREG_XMM0)
+|| }
+|.endmacro
+
+|.macro AVX_OP, avx_ins, reg, op1_reg, addr
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| MEM_OP3_3 avx_ins, xmm(reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), qword, Z_ZV(addr), r0
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| avx_ins xmm(reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), qword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| } else if (Z_MODE(addr) == IS_REG) {
+| avx_ins xmm(reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(Z_REG(addr)-ZREG_XMM0)
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro AVX_MATH, opcode, reg, op1_reg, addr
+|| switch (opcode) {
+|| case ZEND_ADD:
+| AVX_OP vaddsd, reg, op1_reg, addr
+|| break;
+|| case ZEND_SUB:
+| AVX_OP vsubsd, reg, op1_reg, addr
+|| break;
+|| case ZEND_MUL:
+| AVX_OP vmulsd, reg, op1_reg, addr
+|| break;
+|| case ZEND_DIV:
+| AVX_OP vdivsd, reg, op1_reg, addr
+|| break;
+|| }
+|.endmacro
+
+|.macro AVX_MATH_REG, opcode, dst_reg, op1_reg, src_reg
+|| switch (opcode) {
+|| case ZEND_ADD:
+| vaddsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| case ZEND_SUB:
+| vsubsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| case ZEND_MUL:
+| vmulsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| case ZEND_DIV:
+| vdivsd xmm(dst_reg-ZREG_XMM0), xmm(op1_reg-ZREG_XMM0), xmm(src_reg-ZREG_XMM0)
+|| break;
+|| }
+|.endmacro
+
+|.macro LONG_OP, long_ins, reg, addr
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+| .if X64
+|| if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) {
+|| if (reg != ZREG_R0) {
+| mov64 r0, Z_LVAL_P(Z_ZV(addr))
+| long_ins Ra(reg), r0
+|| } else {
+| mov64 r1, Z_LVAL_P(Z_ZV(addr))
+| long_ins Ra(reg), r1
+|| }
+|| } else {
+| long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr))
+|| }
+| .else
+| long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr))
+| .endif
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| long_ins Ra(reg), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| } else if (Z_MODE(addr) == IS_REG) {
+| long_ins Ra(reg), Ra(Z_REG(addr))
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro LONG_OP_WITH_CONST, long_ins, op1_addr, lval
+|| if (Z_MODE(op1_addr) == IS_MEM_ZVAL) {
+| .if X64
+|| if (!IS_SIGNED_32BIT(lval)) {
+| mov64 r0, lval
+| long_ins aword [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)], r0
+|| } else {
+| long_ins aword [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)], lval
+|| }
+| .else
+| long_ins aword [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)], lval
+| .endif
+|| } else if (Z_MODE(op1_addr) == IS_REG) {
+| .if X64
+|| if (!IS_SIGNED_32BIT(lval)) {
+| mov64 r0, lval
+| long_ins Ra(Z_REG(op1_addr)), r0
+|| } else {
+| long_ins Ra(Z_REG(op1_addr)), lval
+|| }
+| .else
+| long_ins Ra(Z_REG(op1_addr)), lval
+| .endif
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro GET_ZVAL_LVAL, reg, addr
+|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
+|| if (Z_LVAL_P(Z_ZV(addr)) == 0) {
+| xor Ra(reg), Ra(reg)
+|| } else {
+| .if X64
+|| if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) {
+| mov64 Ra(reg), Z_LVAL_P(Z_ZV(addr))
+|| } else {
+| mov Ra(reg), Z_LVAL_P(Z_ZV(addr))
+|| }
+| .else
+| mov Ra(reg), Z_LVAL_P(Z_ZV(addr))
+| .endif
+|| }
+|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
+| mov Ra(reg), aword [Ra(Z_REG(addr))+Z_OFFSET(addr)]
+|| } else if (Z_MODE(addr) == IS_REG) {
+|| if (reg != Z_REG(addr)) {
+| mov Ra(reg), Ra(Z_REG(addr))
+|| }
+|| } else {
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro LONG_MATH, opcode, reg, addr
+|| switch (opcode) {
+|| case ZEND_ADD:
+| LONG_OP add, reg, addr
+|| break;
+|| case ZEND_SUB:
+| LONG_OP sub, reg, addr
+|| break;
+|| case ZEND_MUL:
+| LONG_OP imul, reg, addr
+|| break;
+|| case ZEND_BW_OR:
+| LONG_OP or, reg, addr
+|| break;
+|| case ZEND_BW_AND:
+| LONG_OP and, reg, addr
+|| break;
+|| case ZEND_BW_XOR:
+| LONG_OP xor, reg, addr
+|| break;
+|| default:
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro LONG_MATH_REG, opcode, dst_reg, src_reg
+|| switch (opcode) {
+|| case ZEND_ADD:
+| add dst_reg, src_reg
+|| break;
+|| case ZEND_SUB:
+| sub dst_reg, src_reg
+|| break;
+|| case ZEND_MUL:
+| imul dst_reg, src_reg
+|| break;
+|| case ZEND_BW_OR:
+| or dst_reg, src_reg
+|| break;
+|| case ZEND_BW_AND:
+| and dst_reg, src_reg
+|| break;
+|| case ZEND_BW_XOR:
+| xor dst_reg, src_reg
+|| break;
+|| default:
+|| ZEND_ASSERT(0);
+|| }
+|.endmacro
+
+|.macro SET_ZVAL_LVAL, addr, lval
+|| if (Z_MODE(addr) == IS_REG) {
+| mov Ra(Z_REG(addr)), lval
+|| } else {
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| mov aword [Ra(Z_REG(addr))+Z_OFFSET(addr)], lval
+|| }
+|.endmacro
+
+|.macro ZVAL_COPY_CONST, dst_addr, dst_info, dst_def_info, zv, tmp_reg
+|| if (Z_TYPE_P(zv) > IS_TRUE) {
+|| if (Z_TYPE_P(zv) == IS_DOUBLE) {
+|| zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : ZREG_XMM0;
+|| if (Z_DVAL_P(zv) == 0.0 && !is_signed(Z_DVAL_P(zv))) {
+|| if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+| vxorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
+|| } else {
+| xorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
+|| }
+| .if X64
+|| } else if (!IS_32BIT(zv)) {
+| mov64 tmp_reg, ((uintptr_t)zv)
+| SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [tmp_reg]
+| .endif
+|| } else {
+| SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [((uint32_t)(uintptr_t)zv)]
+|| }
+| SSE_SET_ZVAL_DVAL dst_addr, dst_reg
+|| } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
+|| zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : ZREG_XMM0;
+| SSE_GET_LONG dst_reg, Z_LVAL_P(zv)
+| SSE_SET_ZVAL_DVAL dst_addr, dst_reg
+|| } else if (Z_LVAL_P(zv) == 0 && Z_MODE(dst_addr) == IS_REG) {
+| xor Ra(Z_REG(dst_addr)), Ra(Z_REG(dst_addr))
+|| } else {
+| .if X64
+|| if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
+|| if (Z_MODE(dst_addr) == IS_REG) {
+| mov64 Ra(Z_REG(dst_addr)), ((uintptr_t)Z_LVAL_P(zv))
+|| } else {
+| mov64 tmp_reg, ((uintptr_t)Z_LVAL_P(zv))
+| SET_ZVAL_LVAL dst_addr, tmp_reg
+|| }
+|| } else {
+| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
+|| }
+| .else
+| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
+| .endif
+|| }
+|| }
+|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
+|| if (dst_def_info == MAY_BE_DOUBLE) {
+|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != MAY_BE_DOUBLE) {
+| SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE
+|| }
+|| } else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
+| SET_ZVAL_TYPE_INFO dst_addr, Z_TYPE_INFO_P(zv)
+|| }
+|| }
+|.endmacro
+
+|.macro ZVAL_COPY_CONST_2, dst_addr, res_addr, dst_info, dst_def_info, zv, tmp_reg
+|| if (Z_TYPE_P(zv) > IS_TRUE) {
+|| if (Z_TYPE_P(zv) == IS_DOUBLE) {
+|| zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ?
+|| Z_REG(dst_addr) : ((Z_MODE(res_addr) == IS_REG) ? Z_MODE(res_addr) : ZREG_XMM0);
+|| if (Z_DVAL_P(zv) == 0.0 && !is_signed(Z_DVAL_P(zv))) {
+|| if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+| vxorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
+|| } else {
+| xorps xmm(dst_reg-ZREG_XMM0), xmm(dst_reg-ZREG_XMM0)
+|| }
+| .if X64
+|| } else if (!IS_32BIT(zv)) {
+| mov64 tmp_reg, ((uintptr_t)zv)
+| SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [tmp_reg]
+| .endif
+|| } else {
+| SSE_AVX_INS movsd, vmovsd, xmm(dst_reg-ZREG_XMM0), qword [((uint32_t)(uintptr_t)zv)]
+|| }
+| SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
+| SSE_SET_ZVAL_DVAL res_addr, ZREG_XMM0
+|| } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
+|| if (Z_MODE(dst_addr) == IS_REG) {
+| SSE_GET_LONG Z_REG(dst_addr), Z_LVAL_P(zv)
+| SSE_SET_ZVAL_DVAL res_addr, Z_REG(dst_addr)
+|| } else if (Z_MODE(res_addr) == IS_REG) {
+| SSE_GET_LONG Z_REG(res_addr), Z_LVAL_P(zv)
+| SSE_SET_ZVAL_DVAL dst_addr, Z_REG(res_addr)
+|| } else {
+| SSE_GET_LONG ZREG_XMM0, Z_LVAL_P(zv)
+| SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
+| SSE_SET_ZVAL_DVAL res_addr, ZREG_XMM0
+|| }
+|| } else if (Z_LVAL_P(zv) == 0 && (Z_MODE(dst_addr) == IS_REG || Z_MODE(res_addr) == IS_REG)) {
+|| if (Z_MODE(dst_addr) == IS_REG) {
+| xor Ra(Z_REG(dst_addr)), Ra(Z_REG(dst_addr))
+| SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
+|| } else {
+| xor Ra(Z_REG(res_addr)), Ra(Z_REG(res_addr))
+| SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
+|| }
+|| } else {
+| .if X64
+|| if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
+|| if (Z_MODE(dst_addr) == IS_REG) {
+| mov64 Ra(Z_REG(dst_addr)), ((uintptr_t)Z_LVAL_P(zv))
+| SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
+|| } else if (Z_MODE(res_addr) == IS_REG) {
+| mov64 Ra(Z_REG(res_addr)), ((uintptr_t)Z_LVAL_P(zv))
+| SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
+|| } else {
+| mov64 tmp_reg, ((uintptr_t)Z_LVAL_P(zv))
+| SET_ZVAL_LVAL dst_addr, tmp_reg
+| SET_ZVAL_LVAL res_addr, tmp_reg
+|| }
+|| } else if (Z_MODE(dst_addr) == IS_REG) {
+| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
+| SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
+|| } else if (Z_MODE(res_addr) == IS_REG) {
+| SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
+| SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
+|| } else {
+| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
+| SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
+|| }
+| .else
+|| if (Z_MODE(dst_addr) == IS_REG) {
+| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
+| SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
+|| } else if (Z_MODE(res_addr) == IS_REG) {
+| SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
+| SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
+|| } else {
+| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv)
+| SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv)
+|| }
+| .endif
+|| }
+|| }
+|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
+|| if (dst_def_info == MAY_BE_DOUBLE) {
+|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != MAY_BE_DOUBLE) {
+| SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE
+|| }
+|| } else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1<<Z_TYPE_P(zv))) || (dst_info & (MAY_BE_STRING|MAY_BE_ARRAY)) != 0) {
+| SET_ZVAL_TYPE_INFO dst_addr, Z_TYPE_INFO_P(zv)
+|| }
+|| }
+|| if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
+|| if (dst_def_info == MAY_BE_DOUBLE) {
+| SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
+|| } else {
+| SET_ZVAL_TYPE_INFO res_addr, Z_TYPE_INFO_P(zv)
+|| }
+|| }
+|.endmacro
+
+/* the same as above, but "src" may overlap with "tmp_reg1" */
+|.macro ZVAL_COPY_VALUE, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2
+|| if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
+|| if ((src_info & MAY_BE_ANY) == MAY_BE_LONG) {
+|| if (Z_MODE(src_addr) == IS_REG) {
+|| if (Z_MODE(dst_addr) != IS_REG || Z_REG(dst_addr) != Z_REG(src_addr)) {
+| SET_ZVAL_LVAL dst_addr, Ra(Z_REG(src_addr))
+|| }
+|| } else if (Z_MODE(dst_addr) == IS_REG) {
+| GET_ZVAL_LVAL Z_REG(dst_addr), src_addr
+|| } else {
+| GET_ZVAL_LVAL tmp_reg2, src_addr
+| SET_ZVAL_LVAL dst_addr, Ra(tmp_reg2)
+|| }
+|| } else if ((src_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+|| if (Z_MODE(src_addr) == IS_REG) {
+| SSE_SET_ZVAL_DVAL dst_addr, Z_REG(src_addr)
+|| } else if (Z_MODE(dst_addr) == IS_REG) {
+| SSE_GET_ZVAL_DVAL Z_REG(dst_addr), src_addr
+|| } else {
+| SSE_GET_ZVAL_DVAL ZREG_XMM0, src_addr
+| SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
+|| }
+|| } else if (!(src_info & MAY_BE_DOUBLE)) {
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+|| } else {
+| .if X64
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+| .else
+|| if (tmp_reg1 == tmp_reg2 || tmp_reg1 == Z_REG(src_addr)) {
+| GET_ZVAL_W2 Ra(tmp_reg2), src_addr
+| SET_ZVAL_W2 dst_addr, Ra(tmp_reg2)
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+|| } else {
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| GET_ZVAL_W2 Ra(tmp_reg1), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+| SET_ZVAL_W2 dst_addr, Ra(tmp_reg1)
+|| }
+| .endif
+|| }
+|| }
+|| if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+|| has_concrete_type(src_info & MAY_BE_ANY)) {
+|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
+|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
+|| zend_uchar type = concrete_type(src_info);
+| SET_ZVAL_TYPE_INFO dst_addr, type
+|| }
+|| }
+|| } else {
+| GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr
+| SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1)
+|| }
+|.endmacro
+
+|.macro ZVAL_COPY_VALUE_2, dst_addr, dst_info, res_addr, src_addr, src_info, tmp_reg1, tmp_reg2
+|| if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
+|| if ((src_info & MAY_BE_ANY) == MAY_BE_LONG) {
+|| if (Z_MODE(src_addr) == IS_REG) {
+|| if (Z_MODE(dst_addr) != IS_REG || Z_REG(dst_addr) != Z_REG(src_addr)) {
+| SET_ZVAL_LVAL dst_addr, Ra(Z_REG(src_addr))
+|| }
+|| if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != Z_REG(src_addr)) {
+| SET_ZVAL_LVAL res_addr, Ra(Z_REG(src_addr))
+|| }
+|| } else if (Z_MODE(dst_addr) == IS_REG) {
+| GET_ZVAL_LVAL Z_REG(dst_addr), src_addr
+|| if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != Z_REG(dst_addr)) {
+| SET_ZVAL_LVAL res_addr, Ra(Z_REG(dst_addr))
+|| }
+|| } else if (Z_MODE(res_addr) == IS_REG) {
+| GET_ZVAL_LVAL Z_REG(res_addr), src_addr
+| SET_ZVAL_LVAL dst_addr, Ra(Z_REG(res_addr))
+|| } else {
+| GET_ZVAL_LVAL tmp_reg2, src_addr
+| SET_ZVAL_LVAL dst_addr, Ra(tmp_reg2)
+| SET_ZVAL_LVAL res_addr, Ra(tmp_reg2)
+|| }
+|| } else if ((src_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+|| if (Z_MODE(src_addr) == IS_REG) {
+| SSE_SET_ZVAL_DVAL dst_addr, Z_REG(src_addr)
+| SSE_SET_ZVAL_DVAL res_addr, Z_REG(src_addr)
+|| } else if (Z_MODE(dst_addr) == IS_REG) {
+| SSE_GET_ZVAL_DVAL Z_REG(dst_addr), src_addr
+| SSE_SET_ZVAL_DVAL res_addr, Z_REG(dst_addr)
+|| } else if (Z_MODE(res_addr) == IS_REG) {
+| SSE_GET_ZVAL_DVAL Z_REG(res_addr), src_addr
+| SSE_SET_ZVAL_DVAL dst_addr, Z_REG(res_addr)
+|| } else {
+| SSE_GET_ZVAL_DVAL ZREG_XMM0, src_addr
+| SSE_SET_ZVAL_DVAL dst_addr, ZREG_XMM0
+| SSE_SET_ZVAL_DVAL res_addr, ZREG_XMM0
+|| }
+|| } else if (!(src_info & MAY_BE_DOUBLE)) {
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+| SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
+|| } else {
+| .if X64
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+| SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
+| .else
+|| if (tmp_reg1 == tmp_reg2 || tmp_reg1 == Z_REG(src_addr)) {
+| GET_ZVAL_W2 Ra(tmp_reg2), src_addr
+| SET_ZVAL_W2 dst_addr, Ra(tmp_reg2)
+| SET_ZVAL_W2 res_addr, Ra(tmp_reg2)
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+| SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
+|| } else {
+| GET_ZVAL_PTR Ra(tmp_reg2), src_addr
+| GET_ZVAL_W2 Ra(tmp_reg1), src_addr
+| SET_ZVAL_PTR dst_addr, Ra(tmp_reg2)
+| SET_ZVAL_PTR res_addr, Ra(tmp_reg2)
+| SET_ZVAL_W2 dst_addr, Ra(tmp_reg1)
+| SET_ZVAL_W2 res_addr, Ra(tmp_reg1)
+|| }
+| .endif
+|| }
+|| }
+|| if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+|| has_concrete_type(src_info & MAY_BE_ANY)) {
+|| zend_uchar type = concrete_type(src_info);
+|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) {
+|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
+| SET_ZVAL_TYPE_INFO dst_addr, type
+|| }
+|| }
+|| if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
+| SET_ZVAL_TYPE_INFO res_addr, type
+|| }
+|| } else {
+| GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr
+| SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1)
+| SET_ZVAL_TYPE_INFO res_addr, Rd(tmp_reg1)
+|| }
+|.endmacro
+
+|.macro IF_TYPE, type, val, label
+| cmp type, val
+| je label
+|.endmacro
+
+|.macro IF_NOT_TYPE, type, val, label
+| cmp type, val
+| jne label
+|.endmacro
+
+|.macro IF_Z_TYPE, zv, val, label
+| IF_TYPE byte [zv + offsetof(zval, u1.v.type)], val, label
+|.endmacro
+
+|.macro IF_NOT_Z_TYPE, zv, val, label
+| IF_NOT_TYPE byte [zv + offsetof(zval, u1.v.type)], val, label
+|.endmacro
+
+|.macro CMP_ZVAL_TYPE, addr, val
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| cmp byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type)], val
+|.endmacro
+
+|.macro IF_ZVAL_TYPE, addr, val, label
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| IF_TYPE byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type)], val, label
+|.endmacro
+
+|.macro IF_NOT_ZVAL_TYPE, addr, val, label
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| IF_NOT_TYPE byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type)], val, label
+|.endmacro
+
+|.macro IF_FLAGS, type_flags, mask, label
+| test type_flags, mask
+| jnz label
+|.endmacro
+
+|.macro IF_NOT_FLAGS, type_flags, mask, label
+| test type_flags, mask
+| jz label
+|.endmacro
+
+|.macro IF_REFCOUNTED, type_flags, label
+| IF_FLAGS type_flags, IS_TYPE_REFCOUNTED, label
+|.endmacro
+
+|.macro IF_NOT_REFCOUNTED, type_flags, label
+| IF_NOT_FLAGS type_flags, IS_TYPE_REFCOUNTED, label
+|.endmacro
+
+|.macro IF_ZVAL_FLAGS, addr, mask, label
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| IF_FLAGS byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type_flags)], mask, label
+|.endmacro
+
+|.macro IF_NOT_ZVAL_FLAGS, addr, mask, label
+|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
+| IF_NOT_FLAGS byte [Ra(Z_REG(addr))+Z_OFFSET(addr)+offsetof(zval, u1.v.type_flags)], mask, label
+|.endmacro
+
+|.macro IF_ZVAL_REFCOUNTED, addr, label
+| IF_ZVAL_FLAGS addr, IS_TYPE_REFCOUNTED, label
+|.endmacro
+
+|.macro IF_NOT_ZVAL_REFCOUNTED, addr, label
+| IF_NOT_ZVAL_FLAGS addr, IS_TYPE_REFCOUNTED, label
+|.endmacro
+
+|.macro IF_NOT_ZVAL_COLLECTABLE, addr, label
+| IF_NOT_ZVAL_FLAGS addr, IS_TYPE_COLLECTABLE, label
+|.endmacro
+
+|.macro GC_ADDREF, zv
+| add dword [zv], 1
+|.endmacro
+
+|.macro GC_DELREF, zv
+| sub dword [zv], 1
+|.endmacro
+
+|.macro IF_GC_MAY_NOT_LEAK, ptr, tmp_reg, label
+| mov tmp_reg, dword [ptr + 4]
+| and tmp_reg, (GC_INFO_MASK | (GC_COLLECTABLE << GC_FLAGS_SHIFT))
+| cmp tmp_reg, (GC_COLLECTABLE << GC_FLAGS_SHIFT)
+| jne label
+|.endmacro
+
+|.macro ADDREF_CONST, zv, tmp_reg
+| .if X64
+|| if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
+| mov64 tmp_reg, ((uintptr_t)Z_LVAL_P(zv))
+| add dword [tmp_reg], 1
+|| } else {
+| add dword [Z_LVAL_P(zv)], 1
+|| }
+| .else
+| add dword [Z_LVAL_P(zv)], 1
+| .endif
+|.endmacro
+
+|.macro ADDREF_CONST_2, zv, tmp_reg
+| .if X64
+|| if (!IS_SIGNED_32BIT(Z_LVAL_P(zv))) {
+| mov64 tmp_reg, ((uintptr_t)Z_LVAL_P(zv))
+| add dword [tmp_reg], 2
+|| } else {
+| add dword [Z_LVAL_P(zv)], 2
+|| }
+| .else
+| add dword [Z_LVAL_P(zv)], 2
+| .endif
+|.endmacro
+
+|.macro TRY_ADDREF, val_info, type_flags_reg, value_ptr_reg
+|| if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+|| if (val_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+| IF_NOT_REFCOUNTED type_flags_reg, >1
+|| }
+| GC_ADDREF value_ptr_reg
+|1:
+|| }
+|.endmacro
+
+|.macro TRY_ADDREF_2, val_info, type_flags_reg, value_ptr_reg
+|| if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+|| if (val_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+| IF_NOT_REFCOUNTED type_flags_reg, >1
+|| }
+| add dword [value_ptr_reg], 2
+|1:
+|| }
+|.endmacro
+
+|.macro ZVAL_DEREF, reg, info
+|| if (info & MAY_BE_REF) {
+| IF_NOT_Z_TYPE, reg, IS_REFERENCE, >1
+| GET_Z_PTR reg, reg
+| add reg, offsetof(zend_reference, val)
+|1:
+|| }
+|.endmacro
+
+|.macro SAVE_VALID_OPLINE, op
+|| if (op == last_valid_opline) {
+| SAVE_OPLINE
+|| } else {
+| ADDR_OP2_2 mov, aword EX->opline, op, r0
+|| }
+|.endmacro
+
+// zval should be in FCARG1a
+|.macro ZVAL_DTOR_FUNC, var_info, opline // arg1 must be in FCARG1a
+|| do {
+|| if (has_concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+|| zend_uchar type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
+|| if (type == IS_STRING && !ZEND_DEBUG) {
+| EXT_CALL _efree, r0
+|| break;
+|| } else if (type == IS_ARRAY) {
+|| if (opline) {
+| SAVE_VALID_OPLINE opline
+|| }
+| EXT_CALL zend_array_destroy, r0
+|| break;
+|| } else if (type == IS_OBJECT) {
+|| if (opline) {
+| SAVE_VALID_OPLINE opline
+|| }
+| EXT_CALL zend_objects_store_del, r0
+|| break;
+|| }
+|| }
+|| if (opline) {
+| SAVE_VALID_OPLINE opline
+|| }
+| EXT_CALL rc_dtor_func, r0
+|| } while(0);
+|.endmacro
+
+|.macro ZVAL_PTR_DTOR, addr, op_info, gc, cold, safe, opline
+|| if ((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
+|| if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+| // if (Z_REFCOUNTED_P(cv)) {
+|| if (cold) {
+| IF_ZVAL_REFCOUNTED addr, >1
+|.cold_code
+|1:
+|| } else {
+| IF_NOT_ZVAL_REFCOUNTED addr, >4
+|| }
+|| }
+| // if (!Z_DELREF_P(cv)) {
+| GET_ZVAL_PTR FCARG1a, addr
+| GC_DELREF FCARG1a
+|| if (RC_MAY_BE_1(op_info)) {
+|| if (RC_MAY_BE_N(op_info)) {
+|| if (gc && RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
+| jnz >3
+|| } else {
+| jnz >4
+|| }
+|| }
+|| if (safe) {
+| // ZVAL_NULL(cv);
+| SET_ZVAL_TYPE_INFO addr, IS_NULL
+|| }
+| // zval_dtor_func(r);
+| ZVAL_DTOR_FUNC op_info, opline
+|| if (gc && RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
+| jmp >4
+|| }
+|3:
+|| }
+|| if (gc && RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
+|| if ((op_info) & MAY_BE_REF) {
+|| zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, offsetof(zend_reference, val));
+| IF_NOT_ZVAL_TYPE addr, IS_REFERENCE, >1
+| IF_NOT_ZVAL_COLLECTABLE ref_addr, >4
+| GET_ZVAL_PTR FCARG1a, ref_addr
+|1:
+|| }
+| IF_GC_MAY_NOT_LEAK FCARG1a, eax, >4
+| // gc_possible_root(Z_COUNTED_P(z))
+| EXT_CALL gc_possible_root, r0
+|| if (cold && ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) != 0) {
+| jmp >4
+|.code
+|| }
+|| } else if (cold && ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) != 0) {
+| jmp >4
+|.code
+|| }
+|4:
+|| }
+|.endmacro
+
+|.macro FREE_OP, op_type, op, op_info, cold, op_array, opline
+|| if (op_type & (IS_VAR|IS_TMP_VAR)) {
+| ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var), op_info, 0, cold, 0, opline
+|| }
+|.endmacro
+
+|.macro SEPARATE_ARRAY, addr, op_info, cold
+|| if (RC_MAY_BE_N(op_info)) {
+|| zend_reg tmp_reg;
+||
+|| tmp_reg = (Z_REG(addr) == ZREG_FCARG1a) ? ZREG_R0 : ZREG_FCARG1a;
+| GET_ZVAL_LVAL tmp_reg, addr
+|| if (RC_MAY_BE_1(op_info)) {
+| cmp dword [Ra(tmp_reg)], 1 // if (GC_REFCOUNTED() > 1)
+|| if (cold) {
+| ja >1
+|.cold_code
+|1:
+|| } else {
+| jbe >2
+|| }
+|| }
+| IF_NOT_ZVAL_REFCOUNTED addr, >1
+| GC_DELREF Ra(tmp_reg)
+|1:
+|| if (Z_REG(addr) == ZREG_FCARG1a) {
+| mov aword T1, FCARG1a // save
+|| } else {
+| LOAD_ZVAL_ADDR FCARG1a, addr
+|| }
+| EXT_CALL zval_copy_ctor_func, r0
+|| if (Z_REG(addr) == ZREG_FCARG1a) {
+| mov FCARG1a, aword T1 // restore
+|| }
+|| if (RC_MAY_BE_1(op_info)) {
+|| if (cold) {
+| jmp >2
+|.code
+|| }
+|| }
+|2:
+|| }
+| GET_ZVAL_LVAL ZREG_FCARG1a, addr
+|.endmacro
+
+|.macro EFREE_REG_24, op_array, opline
+||#if ZEND_DEBUG
+|| const char *filename = op_array->filename ? op_array->filename->val : NULL;
+| LOAD_ADDR FCARG2a, filename
+| .if X64WIN
+| mov CARG3d, opline->lineno
+| xor CARG4, CARG4
+| mov aword A5, 0
+| EXT_CALL _efree, r0
+| .elif X64
+| mov CARG3d, opline->lineno
+| xor CARG4, CARG4
+| xor CARG5, CARG5
+| EXT_CALL _efree, r0
+| .else
+| sub r4, 4
+| push 0
+| push 0
+| push opline->lineno
+| EXT_CALL _efree, r0
+| add r4, 4
+| .endif
+||#else
+||#ifdef HAVE_BUILTIN_CONSTANT_P
+| EXT_CALL _efree_24, r0
+||#else
+| EXT_CALL _efree, r0
+||#endif
+||#endif
+|.endmacro
+
+|.macro EFREE_24, ptr, op_array, opline
+| mov FCARG1a, ptr
+| EFREE_REG_24 op_array, opline
+|.endmacro
+
+|.macro EMALLOC, size, op_array, opline
+||#if ZEND_DEBUG
+|| const char *filename = op_array->filename ? op_array->filename->val : NULL;
+| mov FCARG1a, size
+| LOAD_ADDR FCARG2a, filename
+| .if X64WIN
+| mov CARG3d, opline->lineno
+| xor CARG4, CARG4
+| mov aword A5, 0
+| EXT_CALL _emalloc, r0
+| .elif X64
+| mov CARG3d, opline->lineno
+| xor CARG4, CARG4
+| xor CARG5, CARG5
+| EXT_CALL _emalloc, r0
+| .else
+| sub r4, 4
+| push 0
+| push 0
+| push opline->lineno
+| EXT_CALL _emalloc, r0
+| add r4, 4
+| .endif
+||#else
+||#ifdef HAVE_BUILTIN_CONSTANT_P
+|| if (size == 24) {
+| EXT_CALL _emalloc_24, r0
+|| } else {
+| mov FCARG1a, size
+| EXT_CALL _emalloc, r0
+|| }
+||#else
+| mov FCARG1a, size
+| EXT_CALL _emalloc, r0
+||#endif
+||#endif
+|.endmacro
+
+|.macro OBJ_RELEASE, reg, tmp_reg, exit_label
+| GC_DELREF reg
+| jne >1
+| // zend_objects_store_del(obj);
+| mov FCARG1a, reg
+| EXT_CALL zend_objects_store_del, r0
+| jmp exit_label
+|1:
+| IF_GC_MAY_NOT_LEAK reg, tmp_reg, >1
+| // gc_possible_root(obj)
+| mov FCARG1a, reg
+| EXT_CALL gc_possible_root, r0
+|1:
+|.endmacro
+
+|.macro UNDEFINED_OFFSET, opline
+|| if (opline == last_valid_opline) {
+| call ->undefined_offset_ex
+|| } else {
+| SAVE_VALID_OPLINE, opline
+| call ->undefined_offset
+|| }
+|.endmacro
+
+|.macro UNDEFINED_INDEX, opline
+|| if (opline == last_valid_opline) {
+| call ->undefined_index_ex
+|| } else {
+| SAVE_VALID_OPLINE, opline
+| call ->undefined_index
+|| }
+|.endmacro
+
+|.macro CANNOT_ADD_ELEMENT, opline
+|| if (opline == last_valid_opline) {
+| call ->cannot_add_element_ex
+|| } else {
+| SAVE_VALID_OPLINE, opline
+| call ->cannot_add_element
+|| }
+|.endmacro
+
+static zend_bool reuse_ip;
+static zend_bool delayed_call_chain;
+static uint32_t delayed_call_level;
+static const zend_op *last_valid_opline;
+static int jit_return_label;
+
+/* bit helpers */
+
+/* from http://aggregate.org/MAGIC/ */
+static uint32_t ones32(uint32_t x)
+{
+ x -= ((x >> 1) & 0x55555555);
+ x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+ x = (((x >> 4) + x) & 0x0f0f0f0f);
+ x += (x >> 8);
+ x += (x >> 16);
+ return x & 0x0000003f;
+}
+
+static uint32_t floor_log2(uint32_t x)
+{
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ return ones32(x) - 1;
+}
+
+static zend_bool is_power_of_two(uint32_t x)
+{
+ return !(x & (x - 1));
+}
+
+static zend_bool has_concrete_type(uint32_t value_type)
+{
+ if (value_type & MAY_BE_UNDEF) {
+ value_type |= MAY_BE_NULL;
+ }
+ value_type &= MAY_BE_ANY;
+ return is_power_of_two (value_type);
+}
+
+static uint32_t concrete_type(uint32_t value_type)
+{
+ return floor_log2(value_type & MAY_BE_ANY);
+}
+
+static inline zend_bool is_signed(double d)
+{
+ return (((unsigned char*)&d)[sizeof(double)-1] & 0x80) != 0;
+}
+
+static int zend_jit_interrupt_handler_stub(dasm_State **Dst)
+{
+ |->interrupt_handler:
+ | //EG(vm_interrupt) = 0;
+ | MEM_OP2_1_ZTS mov, byte, executor_globals, vm_interrupt, 0, r0
+ | //if (EG(timed_out)) {
+ | MEM_OP2_1_ZTS cmp, byte, executor_globals, timed_out, 0, r0
+ | je >1
+ | //zend_timeout(0);
+ | xor FCARG1d, FCARG1d
+ | EXT_CALL zend_timeout, r0
+ |1:
+ | //} else if (zend_interrupt_function) {
+ if (zend_interrupt_function) {
+ | SAVE_OPLINE
+ | //zend_interrupt_function(execute_data);
+ |.if X64
+ | mov CARG1, FP
+ | EXT_CALL zend_interrupt_function, r0
+ |.else
+ | sub r4, 12
+ | push FP
+ | EXT_CALL zend_interrupt_function, r0
+ | add r4, 16
+ |.endif
+ | //ZEND_VM_ENTER();
+ | //execute_data = EG(current_execute_data);
+ | MEM_OP2_2_ZTS mov, FP, aword, executor_globals, current_execute_data, r0
+ | LOAD_OPLINE
+ }
+ | //ZEND_VM_CONTINUE()
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ | add r4, HYBRID_SPAD
+ | JMP_IP
+ } else if (GCC_GLOBAL_REGS) {
+ | add r4, SPAD // stack alignment
+ | JMP_IP
+ } else {
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ | mov r0, 1 // ZEND_VM_ENTER
+ | ret
+ }
+
+ return 1;
+}
+
+static int zend_jit_exception_handler_stub(dasm_State **Dst)
+{
+ |->exception_handler:
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ const void *handler = zend_get_opcode_handler_func(EG(exception_op));
+
+ | add r4, HYBRID_SPAD
+ | EXT_CALL handler, r0
+ | JMP_IP
+ } else {
+ const void *handler = EG(exception_op)->handler;
+
+ if (GCC_GLOBAL_REGS) {
+ | add r4, SPAD // stack alignment
+ } else {
+ | mov FCARG1a, FP
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ }
+ | EXT_JMP handler, r0
+ }
+
+ return 1;
+}
+
+static int zend_jit_exception_handler_undef_stub(dasm_State **Dst)
+{
+ |->exception_handler_undef:
+ | MEM_OP2_2_ZTS mov, r0, aword, executor_globals, opline_before_exception, r0
+ | test byte OP:r0->result_type, (IS_TMP_VAR|IS_VAR)
+ | jnz >1
+ | .if X64
+ | movsxd r0, dword OP:r0->result.var
+ | .else
+ | mov r0, aword OP:r0->result.var
+ | .endif
+ | SET_Z_TYPE_INFO FP + r0, IS_UNDEF
+ |1:
+ | jmp ->exception_handler
+
+ return 1;
+}
+
+static int zend_jit_leave_function_stub(dasm_State **Dst)
+{
+ |->leave_function_handler:
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ | test FCARG1d, ZEND_CALL_TOP
+ | jnz >1
+ | EXT_CALL zend_jit_leave_nested_func_helper, r0
+ | add r4, HYBRID_SPAD // stack alignment
+ | JMP_IP
+ |1:
+ | EXT_CALL zend_jit_leave_top_func_helper, r0
+ | add r4, HYBRID_SPAD // stack alignment
+ | JMP_IP
+ } else {
+ if (GCC_GLOBAL_REGS) {
+ | add r4, SPAD
+ } else {
+ | mov FCARG2a, FP
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD
+ }
+ | test FCARG1d, ZEND_CALL_TOP
+ | jnz >1
+ | EXT_JMP zend_jit_leave_nested_func_helper, r0
+ |1:
+ | EXT_JMP zend_jit_leave_top_func_helper, r0
+ }
+
+ return 1;
+}
+
+static int zend_jit_leave_throw_stub(dasm_State **Dst)
+{
+ |->leave_throw_handler:
+ | // if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
+ if (GCC_GLOBAL_REGS) {
+ | cmp byte OP:IP->opcode, ZEND_HANDLE_EXCEPTION
+ | je >5
+ | // EG(opline_before_exception) = opline;
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, opline_before_exception, IP, r0
+ |5:
+ | // opline = EG(exception_op);
+ | LOAD_IP_ADDR_ZTS executor_globals, exception_op
+ | // HANDLE_EXCEPTION()
+ | jmp ->exception_handler
+ } else {
+ | GET_IP FCARG1a
+ | cmp byte OP:FCARG1a->opcode, ZEND_HANDLE_EXCEPTION
+ | je >5
+ | // EG(opline_before_exception) = opline;
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, opline_before_exception, FCARG1a, r0
+ |5:
+ | // opline = EG(exception_op);
+ | LOAD_IP_ADDR_ZTS executor_globals, exception_op
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ | mov r0, 2 // ZEND_VM_LEAVE
+ | ret
+ }
+
+ return 1;
+}
+
+static int zend_jit_icall_throw_stub(dasm_State **Dst)
+{
+ |->icall_throw_handler:
+ | // zend_throw_exception_internal(NULL);
+ |.if X64
+ | xor CARG1, CARG1
+ | EXT_CALL zend_throw_exception_internal, r0
+ |.else
+ | sub r4, 12
+ | push 0
+ | EXT_CALL zend_throw_exception_internal, r0
+ | add r4, 16
+ |.endif
+ | // HANDLE_EXCEPTION()
+ | jmp ->exception_handler
+
+ return 1;
+}
+
+static int zend_jit_throw_cannot_pass_by_ref_stub(dasm_State **Dst)
+{
+ |->throw_cannot_pass_by_ref:
+ | mov r0, EX->opline
+ |.if X64
+ | movsxd r1, dword OP:r0->result.var
+ |.else
+ | mov r1, OP:r0->result.var
+ |.endif
+ | SET_Z_TYPE_INFO RX+r1, IS_UNDEF
+ | // last EX(call) frame may be delayed
+ | cmp RX, EX->call
+ | je >1
+ | mov r1, EX->call
+ | mov EX:RX->prev_execute_data, r1
+ | mov EX->call, RX
+ |1:
+ | mov RX, r0
+ |.if X64
+ | xor CARG1, CARG1
+ | LOAD_ADDR CARG2, "Cannot pass parameter %d by reference"
+ | mov CARG3d, dword OP:r0->op2.num
+ | EXT_CALL zend_throw_error, r0
+ |.else
+ | mov r1, dword OP:r0->op2.num
+ | sub r4, 4
+ | push r1
+ | push "Cannot pass parameter %d by reference"
+ | push 0
+ | EXT_CALL zend_throw_error, r0
+ | add r4, 16
+ |.endif
+ | cmp byte OP:RX->op1_type, IS_TMP_VAR
+ | jne >9
+ |.if X64
+ | movsxd r0, dword OP:RX->op1.var
+ |.else
+ | mov r0, OP:RX->op1.var
+ |.endif
+ | add r0, FP
+ | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, 0, NULL
+ |9:
+ | jmp ->exception_handler
+
+ return 1;
+}
+
+static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst)
+{
+ |->undefined_offset_ex:
+ | SAVE_OPLINE
+ | jmp ->undefined_offset
+
+ return 1;
+}
+
+static int zend_jit_undefined_offset_stub(dasm_State **Dst)
+{
+ |->undefined_offset:
+ |.if X64WIN
+ | sub r4, 0x28
+ |.elif X64
+ | sub r4, 8
+ |.else
+ | sub r4, 12
+ |.endif
+ | mov r0, EX->opline
+ |.if X64
+ | movsxd r1, dword OP:r0->result.var
+ |.else
+ | mov r1, OP:r0->result.var
+ |.endif
+ | cmp byte OP:r0->op2_type, IS_CONST
+ | SET_Z_TYPE_INFO FP + r1, IS_NULL
+ | jne >2
+ |.if X64
+ | movsxd r1, dword OP:r0->op2.constant
+ | add r0, r1
+ |.else
+ | mov r0, aword OP:r0->op2.zv
+ |.endif
+ | jmp >3
+ |2:
+ |.if X64
+ | movsxd r0, dword OP:r0->op2.var
+ |.else
+ | mov r0, OP:r0->op2.var
+ |.endif
+ | add r0, FP
+ |3:
+ |.if X64WIN
+ | mov CARG1, E_NOTICE
+ | LOAD_ADDR CARG2, "Undefined offset: " ZEND_LONG_FMT
+ | mov CARG3, aword [r0]
+ | EXT_CALL zend_error, r0
+ | add r4, 0x28 // stack alignment
+ |.elif X64
+ | mov CARG1, E_NOTICE
+ | LOAD_ADDR CARG2, "Undefined offset: " ZEND_LONG_FMT
+ | mov CARG3, aword [r0]
+ | EXT_CALL zend_error, r0
+ | add r4, 8 // stack alignment
+ |.else
+ | sub r4, 4
+ | push aword [r0]
+ | push "Undefined offset: " ZEND_LONG_FMT
+ | push E_NOTICE
+ | EXT_CALL zend_error, r0
+ | add r4, 28
+ |.endif
+ | ret
+
+ return 1;
+}
+
+static int zend_jit_undefined_index_ex_stub(dasm_State **Dst)
+{
+ |->undefined_index_ex:
+ | SAVE_OPLINE
+ | jmp ->undefined_index
+
+ return 1;
+}
+
+static int zend_jit_undefined_index_stub(dasm_State **Dst)
+{
+ |->undefined_index:
+ |.if X64WIN
+ | sub r4, 0x28
+ |.elif X64
+ | sub r4, 8
+ |.else
+ | sub r4, 12
+ |.endif
+ | mov r0, EX->opline
+ |.if X64
+ | movsxd r1, dword OP:r0->result.var
+ |.else
+ | mov r1, OP:r0->result.var
+ |.endif
+ | cmp byte OP:r0->op2_type, IS_CONST
+ | SET_Z_TYPE_INFO FP + r1, IS_NULL
+ | jne >2
+ |.if X64
+ | movsxd r1, dword OP:r0->op2.constant
+ | add r0, r1
+ |.else
+ | mov r0, aword OP:r0->op2.zv
+ |.endif
+ | jmp >3
+ |2:
+ |.if X64
+ | movsxd r0, dword OP:r0->op2.var
+ |.else
+ | mov r0, OP:r0->op2.var
+ |.endif
+ | add r0, FP
+ |3:
+ |.if X64WIN
+ | mov CARG1, E_NOTICE
+ | LOAD_ADDR CARG2, "Undefined index: %s"
+ | mov CARG3, aword [r0]
+ | add CARG3, offsetof(zend_string, val)
+ | EXT_CALL zend_error, r0
+ | add r4, 0x28
+ |.elif X64
+ | mov CARG1, E_NOTICE
+ | LOAD_ADDR CARG2, "Undefined index: %s"
+ | mov CARG3, aword [r0]
+ | add CARG3, offsetof(zend_string, val)
+ | EXT_CALL zend_error, r0
+ | add r4, 8
+ |.else
+ | sub r4, 4
+ | mov r0, aword [r0]
+ | add r0, offsetof(zend_string, val)
+ | push r0
+ | push "Undefined index: %s"
+ | push E_NOTICE
+ | EXT_CALL zend_error, r0
+ | add r4, 28
+ |.endif
+ | ret
+
+ return 1;
+}
+
+static int zend_jit_cannot_add_element_ex_stub(dasm_State **Dst)
+{
+ |->cannot_add_element_ex:
+ | SAVE_OPLINE
+ | jmp ->cannot_add_element
+
+ return 1;
+}
+
+static int zend_jit_cannot_add_element_stub(dasm_State **Dst)
+{
+ |->cannot_add_element:
+ |.if X64WIN
+ | sub r4, 0x28
+ |.elif X64
+ | sub r4, 8
+ |.else
+ | sub r4, 12
+ |.endif
+ | mov r0, EX->opline
+ | cmp byte OP:r0->result_type, IS_UNUSED
+ | jz >1
+ |.if X64
+ | movsxd r0, dword OP:r0->result.var
+ |.else
+ | mov r0, OP:r0->result.var
+ |.endif
+ | SET_Z_TYPE_INFO FP + r0, IS_NULL
+ |1:
+ |.if X64WIN
+ | xor CARG1, CARG1
+ | LOAD_ADDR CARG2, "Cannot add element to the array as the next element is already occupied"
+ | EXT_CALL zend_throw_error, r0
+ | add r4, 0x28
+ |.elif X64
+ | xor CARG1, CARG1
+ | LOAD_ADDR CARG2, "Cannot add element to the array as the next element is already occupied"
+ | EXT_CALL zend_throw_error, r0
+ | add r4, 8
+ |.else
+ | sub r4, 8
+ | push "Cannot add element to the array as the next element is already occupied"
+ | push 0
+ | EXT_CALL zend_throw_error, r0
+ | add r4, 28
+ |.endif
+ | ret
+
+ return 1;
+}
+
+static int zend_jit_undefined_function_stub(dasm_State **Dst)
+{
+ |->undefined_function:
+ | mov r0, aword EX->opline
+ |.if X64
+ | xor CARG1, CARG1
+ | LOAD_ADDR CARG2, "Call to undefined function %s()"
+ | movsxd CARG3, dword [r0 + offsetof(zend_op, op2.constant)]
+ | mov CARG3, aword [r0 + CARG3]
+ | add CARG3, offsetof(zend_string, val)
+ | EXT_CALL zend_throw_error, r0
+ |.else
+ | sub r4, 4
+ | mov r0, aword [r0 + offsetof(zend_op, op2.zv)]
+ | mov r0, aword [r0]
+ | add r0, offsetof(zend_string, val)
+ | push r0
+ | push "Call to undefined function %s()"
+ | push 0
+ | EXT_CALL zend_throw_error, r0
+ | add r4, 16
+ |.endif
+ | jmp ->exception_handler
+ return 1;
+}
+
+static int zend_jit_negative_shift_stub(dasm_State **Dst)
+{
+ |->negative_shift:
+ | UNDEF_OPLINE_RESULT
+ |.if X64
+ |.if WIN
+ | LOAD_ADDR CARG1, &zend_ce_arithmetic_error
+ | mov CARG1, aword [CARG1]
+ |.else
+ | LOAD_ADDR CARG1, zend_ce_arithmetic_error
+ |.endif
+ | LOAD_ADDR CARG2, "Bit shift by negative number"
+ | EXT_CALL zend_throw_error, r0
+ |.else
+ | sub r4, 8
+ | push "Bit shift by negative number"
+ |.if WIN
+ | LOAD_ADDR r0, &zend_ce_arithmetic_error
+ | push aword [r0]
+ |.else
+ | PUSH_ADDR zend_ce_arithmetic_error, r0
+ |.endif
+ | EXT_CALL zend_throw_error, r0
+ | add r4, 16
+ |.endif
+ | jmp ->exception_handler
+ return 1;
+}
+
+static int zend_jit_mod_by_zero_stub(dasm_State **Dst)
+{
+ |->mod_by_zero:
+ | UNDEF_OPLINE_RESULT
+ |.if X64
+ |.if WIN
+ | LOAD_ADDR CARG1, &zend_ce_division_by_zero_error
+ | mov CARG1, aword [CARG1]
+ |.else
+ | LOAD_ADDR CARG1, zend_ce_division_by_zero_error
+ |.endif
+ | LOAD_ADDR CARG2, "Modulo by zero"
+ | EXT_CALL zend_throw_error, r0
+ |.else
+ | sub r4, 8
+ | push "Modulo by zero"
+ |.if WIN
+ | LOAD_ADDR r0, &zend_ce_division_by_zero_error
+ | push aword [r0]
+ |.else
+ | PUSH_ADDR zend_ce_division_by_zero_error, r0
+ |.endif
+ | EXT_CALL zend_throw_error, r0
+ | add r4, 16
+ |.endif
+ | jmp ->exception_handler
+ return 1;
+}
+
+static int zend_jit_double_one_stub(dasm_State **Dst)
+{
+ |->one:
+ |.dword 0, 0x3ff00000
+ return 1;
+}
+
+static int zend_jit_hybrid_runtime_jit_stub(dasm_State **Dst)
+{
+ |->hybrid_runtime_jit:
+ | EXT_CALL zend_runtime_jit, r0
+ | JMP_IP
+ return 1;
+}
+
+static int zend_jit_hybrid_profile_jit_stub(dasm_State **Dst)
+{
+ |->hybrid_profile_jit:
+ | // ++zend_jit_profile_counter;
+ | .if X64
+ | LOAD_ADDR r0, &zend_jit_profile_counter
+ | inc aword [r0]
+ | .else
+ | inc aword [&zend_jit_profile_counter]
+ | .endif
+ | // op_array = (zend_op_array*)EX(func);
+ | mov r0, EX->func
+ | // ++ZEND_COUNTER_INFO(op_array)
+ | mov r2, aword [r0 + offsetof(zend_op_array, run_time_cache__ptr)]
+#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
+ | mov r2, aword [r2]
+#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
+ | test r2, 1
+ | jz >1
+ | MEM_OP2_2_ZTS add, r2, aword, compiler_globals, map_ptr_base, r1
+ |1:
+ | mov r2, aword [r2]
+#else
+# error "Unknown ZEND_MAP_PTR_KIND"
+#endif
+ | inc aword [r2 + zend_jit_profile_counter_rid * sizeof(void*)]
+ | // handler = (const void*)ZEND_FUNC_INFO(op_array);
+ | mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
+ | // return ((zend_vm_opcode_handler_t)handler)();
+ | jmp r0
+ return 1;
+}
+
+/*
+ * This code is based Mike Pall's "Hashed profile counters" idea, implemented
+ * in LuaJIT. The full description may be found in "LuaJIT 2.0 intellectual
+ * property disclosure and research opportunities" email
+ * at http://lua-users.org/lists/lua-l/2009-11/msg00089.html
+ *
+ * In addition we use a variation of Knuth's multiplicative hash function
+ * described at https://code.i-harness.com/en/q/a21ce
+ *
+ * uint64_t hash(uint64_t x) {
+ * x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
+ * x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
+ * x = x ^ (x >> 31);
+ * return x;
+ * }
+ *
+ * uint_32_t hash(uint32_t x) {
+ * x = ((x >> 16) ^ x) * 0x45d9f3b;
+ * x = ((x >> 16) ^ x) * 0x45d9f3b;
+ * x = (x >> 16) ^ x;
+ * return x;
+ * }
+ *
+ */
+static int zend_jit_hybrid_func_counter_stub(dasm_State **Dst)
+{
+ |->hybrid_func_counter:
+ | mov r0, EX->func
+ | mov r1, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
+ | mov r2, aword [r1]
+ | sub word [r2], ZEND_JIT_HOT_FUNC_COST
+ | jle >1
+ | GET_IP r2
+ | sub r2, aword [r0 + offsetof(zend_op_array, opcodes)]
+ | // divide by sizeof(zend_op)
+ | .if X64
+ || ZEND_ASSERT(sizeof(zend_op) == 32);
+ | sar r2, 5
+ | .else
+ || ZEND_ASSERT(sizeof(zend_op) == 28);
+ | sar r2, 2
+ | imul r2, 0xb6db6db7
+ | .endif
+ | .if X64
+ | jmp aword [r1+r2*8+8]
+ | .else
+ | jmp aword [r1+r2*4+4]
+ | .endif
+ |1:
+ | mov FCARG1a, FP
+ | GET_IP FCARG2a
+ | EXT_CALL zend_jit_hot_func, r0
+ | JMP_IP
+ return 1;
+}
+
+static int zend_jit_hybrid_loop_counter_stub(dasm_State **Dst)
+{
+ |->hybrid_loop_counter:
+ | mov r0, EX->func
+ | mov r1, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])]
+ | mov r2, aword [r1]
+ | sub word [r2], ZEND_JIT_HOT_LOOP_COST
+ | jle >1
+ | GET_IP r2
+ | sub r2, aword [r0 + offsetof(zend_op_array, opcodes)]
+ | // divide by sizeof(zend_op)
+ | .if X64
+ || ZEND_ASSERT(sizeof(zend_op) == 32);
+ | sar r2, 5
+ | .else
+ || ZEND_ASSERT(sizeof(zend_op) == 28);
+ | sar r2, 2
+ | imul r2, 0xb6db6db7
+ | .endif
+ | .if X64
+ | jmp aword [r1+r2*8+8]
+ | .else
+ | jmp aword [r1+r2*4+4]
+ | .endif
+ |1:
+ | mov FCARG1a, FP
+ | GET_IP FCARG2a
+ | EXT_CALL zend_jit_hot_func, r0
+ | JMP_IP
+ return 1;
+}
+
+#ifdef CONTEXT_THREADED_JIT
+static int zend_jit_context_threaded_call_stub(dasm_State **Dst)
+{
+ |->context_threaded_call:
+ | pop r0
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ | add r4, HYBRID_SPAD
+ | jmp aword [IP]
+ } else if (GCC_GLOBAL_REGS) {
+ | add r4, SPAD // stack alignment
+ | jmp aword [IP]
+ } else {
+ ZEND_ASSERT(0);
+ // TODO: context threading can't work without GLOBAL REGS because we have to change
+ // the value of execute_data in execute_ex()
+ | mov FCARG1a, FP
+ | mov r0, aword [FP]
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ | jmp aword [r0]
+ }
+ return 1;
+}
+#endif
+
+static const zend_jit_stub zend_jit_stubs[] = {
+ JIT_STUB(interrupt_handler),
+ JIT_STUB(exception_handler),
+ JIT_STUB(exception_handler_undef),
+ JIT_STUB(leave_function),
+ JIT_STUB(leave_throw),
+ JIT_STUB(icall_throw),
+ JIT_STUB(throw_cannot_pass_by_ref),
+ JIT_STUB(undefined_offset),
+ JIT_STUB(undefined_index),
+ JIT_STUB(cannot_add_element),
+ JIT_STUB(undefined_offset_ex),
+ JIT_STUB(undefined_index_ex),
+ JIT_STUB(cannot_add_element_ex),
+ JIT_STUB(undefined_function),
+ JIT_STUB(negative_shift),
+ JIT_STUB(mod_by_zero),
+ JIT_STUB(double_one),
+#ifdef CONTEXT_THREADED_JIT
+ JIT_STUB(context_threaded_call),
+#endif
+};
+
+#if ZTS && defined(ZEND_WIN32)
+extern uint32_t _tls_index;
+extern char *_tls_start;
+extern char *_tls_end;
+#endif
+
+static int zend_jit_setup(void)
+{
+ if (!zend_cpu_supports(ZEND_CPU_FEATURE_SSE2)) {
+ zend_error(E_CORE_ERROR, "CPU doesn't support SSE2");
+ return FAILURE;
+ }
+ if (zend_jit_cpu_flags & ZEND_JIT_CPU_AVX) {
+ if (zend_cpu_supports(ZEND_CPU_FEATURE_AVX)) {
+ zend_jit_x86_flags |= ZEND_JIT_CPU_AVX;
+ }
+ }
+
+#if ZTS
+# ifdef _WIN64
+ tsrm_tls_index = _tls_index * sizeof(void*);
+
+ /* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
+ /* Probably, it might be better solution */
+ do {
+ void ***tls_mem = ((void***)__readgsqword(0x58))[_tls_index];
+ void *val = _tsrm_ls_cache;
+ size_t offset = 0;
+ size_t size = (char*)&_tls_end - (char*)&_tls_start;
+
+ while (offset < size) {
+ if (*tls_mem == val) {
+ tsrm_tls_offset = offset;
+ break;
+ }
+ tls_mem++;
+ offset += sizeof(void*);
+ }
+ if (offset >= size) {
+ // TODO: error message ???
+ return FAILURE;
+ }
+ } while(0);
+# elif ZEND_WIN32
+ tsrm_tls_index = _tls_index * sizeof(void*);
+
+ /* To find offset of "_tsrm_ls_cache" in TLS segment we perform a linear scan of local TLS memory */
+ /* Probably, it might be better solution */
+ do {
+ void ***tls_mem = ((void***)__readfsdword(0x2c))[_tls_index];
+ void *val = _tsrm_ls_cache;
+ size_t offset = 0;
+ size_t size = (char*)&_tls_end - (char*)&_tls_start;
+
+ while (offset < size) {
+ if (*tls_mem == val) {
+ tsrm_tls_offset = offset;
+ break;
+ }
+ tls_mem++;
+ offset += sizeof(void*);
+ }
+ if (offset >= size) {
+ // TODO: error message ???
+ return FAILURE;
+ }
+ } while(0);
+# elif defined(__APPLE__) && defined(__x86_64__)
+ tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
+ if (tsrm_ls_cache_tcb_offset == 0) {
+ size_t *ti;
+ __asm__(
+ "leaq __tsrm_ls_cache(%%rip),%0"
+ : "=r" (ti));
+ tsrm_tls_offset = ti[2];
+ tsrm_tls_index = ti[1] * 8;
+ }
+# elif defined(__GNUC__) && defined(__x86_64__)
+ tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
+ if (tsrm_ls_cache_tcb_offset == 0) {
+#if defined(__has_attribute) && __has_attribute(tls_model)
+ size_t ret;
+
+ asm ("movq _tsrm_ls_cache@gottpoff(%%rip),%0"
+ : "=r" (ret));
+ tsrm_ls_cache_tcb_offset = ret;
+#else
+ size_t *ti;
+
+ __asm__(
+ "leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
+ : "=a" (ti));
+ tsrm_tls_offset = ti[1];
+ tsrm_tls_index = ti[0] * 16;
+#endif
+ }
+# elif defined(__GNUC__) && defined(__i386__)
+ tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset();
+ if (tsrm_ls_cache_tcb_offset == 0) {
+#if 1
+ size_t ret;
+
+ asm ("leal _tsrm_ls_cache@ntpoff,%0\n"
+ : "=a" (ret));
+ tsrm_ls_cache_tcb_offset = ret;
+#else
+ size_t *ti, _ebx, _ecx, _edx;
+
+ __asm__(
+ "call 1f\n"
+ ".subsection 1\n"
+ "1:\tmovl (%%esp), %%ebx\n\t"
+ "ret\n"
+ ".previous\n\t"
+ "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t"
+ "leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n\t"
+ "call ___tls_get_addr@plt\n\t"
+ "leal _tsrm_ls_cache@tlsldm(%%ebx), %0\n"
+ : "=a" (ti), "=&b" (_ebx), "=&c" (_ecx), "=&d" (_edx));
+ tsrm_tls_offset = ti[1];
+ tsrm_tls_index = ti[0] * 8;
+#endif
+ }
+# endif
+#endif
+
+ return SUCCESS;
+}
+
+static int zend_jit_align_func(dasm_State **Dst)
+{
+ reuse_ip = 0;
+ delayed_call_chain = 0;
+ last_valid_opline = NULL;
+ jit_return_label = -1;
+ |.align 16
+ return 1;
+}
+
+static int zend_jit_prologue(dasm_State **Dst)
+{
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ | sub r4, HYBRID_SPAD
+ } else if (GCC_GLOBAL_REGS) {
+ | sub r4, SPAD // stack alignment
+ } else {
+ | sub r4, NR_SPAD // stack alignment
+ | mov aword T2, FP // save FP
+ | mov aword T3, RX // save IP
+ | mov FP, FCARG1a
+ }
+ return 1;
+}
+
+static int zend_jit_label(dasm_State **Dst, unsigned int label)
+{
+ |=>label:
+ return 1;
+}
+
+static int zend_jit_save_call_chain(dasm_State **Dst, uint32_t call_level)
+{
+ | // call->prev_execute_data = EX(call);
+ if (call_level == 1) {
+ | mov aword EX:RX->prev_execute_data, 0
+ } else {
+ | mov r0, EX->call
+ | mov EX:RX->prev_execute_data, r0
+ }
+ | // EX(call) = call;
+ | mov EX->call, RX
+
+ delayed_call_chain = 0;
+
+ return 1;
+}
+
+static int zend_jit_set_ip(dasm_State **Dst, const zend_op *opline)
+{
+ if (!last_valid_opline) {
+ | LOAD_IP_ADDR opline
+ } else if (last_valid_opline != opline) {
+ if (GCC_GLOBAL_REGS) {
+ | ADD_IP (opline - last_valid_opline) * sizeof(zend_op);
+ } else {
+ | LOAD_IP_ADDR opline
+ }
+ }
+ return 1;
+}
+
+static int zend_jit_set_valid_ip(dasm_State **Dst, const zend_op *opline)
+{
+ if (delayed_call_chain) {
+ if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
+ return 0;
+ }
+ }
+ if (!zend_jit_set_ip(Dst, opline)) {
+ return 0;
+ }
+ last_valid_opline = opline;
+ reuse_ip = 0;
+ return 1;
+}
+
+static int zend_jit_check_timeout(dasm_State **Dst, const zend_op *opline)
+{
+#if 0
+ if (!zend_jit_set_valid_ip(Dst, opline)) {
+ return 0;
+ }
+ | MEM_OP2_1_ZTS cmp, byte, executor_globals, vm_interrupt, 0, r0
+ | jne ->interrupt_handler
+#else
+ | MEM_OP2_1_ZTS cmp, byte, executor_globals, vm_interrupt, 0, r0
+ if (last_valid_opline == opline) {
+ | jne ->interrupt_handler
+ } else {
+ | jne >1
+ |.cold_code
+ |1:
+ | LOAD_IP_ADDR opline
+ | jmp ->interrupt_handler
+ |.code
+ }
+#endif
+ return 1;
+}
+
+static int zend_jit_check_exception(dasm_State **Dst)
+{
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | jne ->exception_handler
+ return 1;
+}
+
+static int zend_jit_check_exception_undef_result(dasm_State **Dst, const zend_op *opline)
+{
+ if (opline->result_type & (IS_TMP_VAR|IS_VAR)) {
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | jne ->exception_handler_undef
+ return 1;
+ }
+ return zend_jit_check_exception(Dst);
+}
+
+static int zend_jit_handler(dasm_State **Dst, const zend_op *opline, int may_throw)
+{
+ const void *handler;
+
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ handler = zend_get_opcode_handler_func(opline);
+ } else {
+ handler = opline->handler;
+ }
+
+ if (!zend_jit_set_valid_ip(Dst, opline)) {
+ return 0;
+ }
+ if (!GCC_GLOBAL_REGS) {
+ | mov FCARG1a, FP
+ }
+ | EXT_CALL handler, r0
+ if (may_throw) {
+ zend_jit_check_exception(Dst);
+ }
+ last_valid_opline++;
+
+ /* Skip the following OP_DATA */
+ switch (opline->opcode) {
+ case ZEND_ASSIGN_DIM:
+ case ZEND_ASSIGN_OBJ:
+ case ZEND_ASSIGN_STATIC_PROP:
+ case ZEND_ASSIGN_DIM_OP:
+ case ZEND_ASSIGN_OBJ_OP:
+ case ZEND_ASSIGN_STATIC_PROP_OP:
+ case ZEND_ASSIGN_STATIC_PROP_REF:
+ case ZEND_ASSIGN_OBJ_REF:
+ last_valid_opline++;
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+static int zend_jit_tail_handler(dasm_State **Dst, const zend_op *opline)
+{
+ if (!zend_jit_set_valid_ip(Dst, opline)) {
+ return 0;
+ }
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ if (opline->opcode == ZEND_DO_UCALL ||
+ opline->opcode == ZEND_DO_FCALL_BY_NAME ||
+ opline->opcode == ZEND_DO_FCALL ||
+ opline->opcode == ZEND_RETURN) {
+
+ /* Use inlined HYBRID VM handler */
+ const void *handler = opline->handler;
+
+ | add r4, HYBRID_SPAD
+ | EXT_JMP handler, r0
+ } else {
+ const void *handler = zend_get_opcode_handler_func(opline);
+
+ | EXT_CALL handler, r0
+ | add r4, HYBRID_SPAD
+ | JMP_IP
+ }
+ } else {
+ const void *handler = opline->handler;
+
+ if (GCC_GLOBAL_REGS) {
+ | add r4, SPAD // stack alignment
+ } else {
+ | mov FCARG1a, FP
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ }
+ | EXT_JMP handler, r0
+ }
+ last_valid_opline = NULL;
+ return 1;
+}
+
+static int zend_jit_set_opline(dasm_State **Dst, const zend_op *target_opline)
+{
+ if (!reuse_ip) {
+ last_valid_opline = target_opline;
+ }
+ return 1;
+}
+
+static int zend_jit_reset_opline(dasm_State **Dst, const zend_op *target_opline)
+{
+ last_valid_opline = NULL;
+ return 1;
+}
+
+static void zend_jit_start_reuse_ip(void) {
+ last_valid_opline = NULL;
+ reuse_ip = 1;
+}
+
+static void zend_jit_stop_reuse_ip(void) {
+ reuse_ip = 0;
+}
+
+static int zend_jit_jmp(dasm_State **Dst, unsigned int target_label)
+{
+ | jmp =>target_label
+ return 1;
+}
+
+static int zend_jit_cond_jmp(dasm_State **Dst, const zend_op *next_opline, unsigned int target_label)
+{
+ | CMP_IP next_opline
+ | jne =>target_label
+
+ last_valid_opline = next_opline;
+
+ return 1;
+}
+
+#ifdef CONTEXT_THREADED_JIT
+static int zend_jit_context_threaded_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block)
+{
+ if (!zend_jit_handler(Dst, opline, 1)) return 0;
+ if (opline->opcode == ZEND_DO_UCALL) {
+ | call ->context_threaded_call
+ } else {
+ const zend_op *next_opline = opline + 1;
+
+ | CMP_IP next_opline
+ | je =>next_block
+ | call ->context_threaded_call
+ }
+ return 1;
+}
+#endif
+
+static int zend_jit_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block)
+{
+#ifdef CONTEXT_THREADED_JIT
+ return zend_jit_context_threaded_call(Dst, opline, next_block);
+#else
+ return zend_jit_tail_handler(Dst, opline);
+#endif
+}
+
+static int zend_jit_spill_store(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info, zend_bool set_type)
+{
+ ZEND_ASSERT(Z_MODE(src) == IS_REG);
+ ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
+
+ if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
+ | SET_ZVAL_LVAL dst, Ra(Z_REG(src))
+ if (set_type) {
+ | SET_ZVAL_TYPE_INFO dst, IS_LONG
+ }
+ } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+ | SSE_SET_ZVAL_DVAL dst, Z_REG(src)
+ if (set_type) {
+ | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ return 1;
+}
+
+static int zend_jit_load_reg(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
+{
+ ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
+ ZEND_ASSERT(Z_MODE(dst) == IS_REG);
+
+ if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
+ | GET_ZVAL_LVAL Z_REG(dst), src
+ } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+ | SSE_GET_ZVAL_DVAL Z_REG(dst), src
+ } else {
+ ZEND_ASSERT(0);
+ }
+ return 1;
+}
+
+static int zend_jit_store_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg)
+{
+ zend_jit_addr src = ZEND_ADDR_REG(reg);
+ zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (uint32_t)(uintptr_t)ZEND_CALL_VAR_NUM(NULL, var));
+
+ return zend_jit_spill_store(Dst, src, dst, info, 1);
+}
+
+static int zend_jit_store_var_if_necessary(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info)
+{
+ if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
+ zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (uint32_t)(uintptr_t)ZEND_CALL_VAR(NULL, var));
+ return zend_jit_spill_store(Dst, src, dst, info, 1);
+ }
+ return 1;
+}
+
+static int zend_jit_store_var_if_necessary_ex(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info, zend_jit_addr old, uint32_t old_info)
+{
+ if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
+ zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (uint32_t)(uintptr_t)ZEND_CALL_VAR(NULL, var));
+ zend_bool set_type = 1;
+
+ if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
+ (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
+ if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
+ set_type = 0;
+ }
+ }
+ return zend_jit_spill_store(Dst, src, dst, info, set_type);
+ }
+ return 1;
+}
+
+static int zend_jit_load_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg)
+{
+ zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (uint32_t)(uintptr_t)ZEND_CALL_VAR_NUM(NULL, var));
+ zend_jit_addr dst = ZEND_ADDR_REG(reg);
+
+ return zend_jit_load_reg(Dst, src, dst, info);
+}
+
+static int zend_jit_update_regs(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
+{
+ if (!zend_jit_same_addr(src, dst)) {
+ if (Z_MODE(src) == IS_REG) {
+ if (Z_MODE(dst) == IS_REG) {
+ if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
+ | mov Ra(Z_REG(dst)), Ra(Z_REG(src))
+ } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+ | SSE_AVX_INS movsd, vmovaps, xmm(Z_REG(dst)-ZREG_XMM0), xmm(Z_REG(src)-ZREG_XMM0)
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else if (Z_MODE(dst) == IS_MEM_ZVAL) {
+ if (!Z_LOAD(src) && !Z_STORE(src)) {
+ if (!zend_jit_spill_store(Dst, src, dst, info, 1)) {
+ return 0;
+ }
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else if (Z_MODE(src) == IS_MEM_ZVAL) {
+ if (Z_MODE(dst) == IS_REG) {
+ if (!zend_jit_load_reg(Dst, src, dst, info)) {
+ return 0;
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ }
+ return 1;
+}
+
+static int zend_jit_inc_dec(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow)
+{
+ if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2
+ }
+ if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
+ | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_LONG, ZREG_R0, ZREG_R1
+ }
+ if (!zend_jit_update_regs(Dst, op1_addr, op1_def_addr, MAY_BE_LONG)) {
+ return 0;
+ }
+ if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
+ | LONG_OP_WITH_CONST add, op1_def_addr, Z_L(1)
+ } else {
+ | LONG_OP_WITH_CONST sub, op1_def_addr, Z_L(1)
+ }
+
+ if (may_overflow) {
+ | jo >1
+ if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
+ opline->result_type != IS_UNUSED) {
+ | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_R0, ZREG_R1
+ }
+ |.cold_code
+ |1:
+ if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
+ |.if X64
+ | mov64 rax, 0x43e0000000000000
+ | SET_ZVAL_LVAL op1_def_addr, rax
+ |.else
+ | SET_ZVAL_LVAL op1_def_addr, 0
+ | SET_ZVAL_W2 op1_def_addr, 0x41e00000
+ |.endif
+ } else {
+ |.if X64
+ | mov64 rax, 0xc3e0000000000000
+ | SET_ZVAL_LVAL op1_def_addr, rax
+ |.else
+ | SET_ZVAL_LVAL op1_def_addr, 0x00200000
+ | SET_ZVAL_W2 op1_def_addr, 0xc1e00000
+ |.endif
+ }
+ | SET_ZVAL_TYPE_INFO op1_def_addr, IS_DOUBLE
+ if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
+ opline->result_type != IS_UNUSED) {
+ | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_DOUBLE, ZREG_R0, ZREG_R1
+ }
+ | jmp >3
+ |.code
+ } else {
+ if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
+ opline->result_type != IS_UNUSED) {
+ | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_R0, ZREG_R1
+ }
+ }
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
+ |.cold_code
+ |2:
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | SAVE_VALID_OPLINE opline
+ if (op1_info & MAY_BE_UNDEF) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >2
+ | // zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
+ | mov FCARG1d, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL
+ op1_info |= MAY_BE_NULL;
+ }
+ |2:
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+
+ | // ZVAL_DEREF(var_ptr);
+ if (op1_info & MAY_BE_REF) {
+ | IF_NOT_Z_TYPE, FCARG1a, IS_REFERENCE, >2
+ | GET_Z_PTR FCARG2a, FCARG1a
+ | cmp aword [FCARG2a + offsetof(zend_reference, sources.ptr)], 0
+ | lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
+ | jz >2
+ |.if X64
+ if (RETURN_VALUE_USED(opline)) {
+ | LOAD_ZVAL_ADDR CARG3, res_addr
+ } else {
+ | mov CARG3, 0
+ }
+ |.else
+ | sub r4, 12
+ if (RETURN_VALUE_USED(opline)) {
+ | PUSH_ZVAL_ADDR res_addr, r0
+ } else {
+ | push 0
+ }
+ |.endif
+ if (opline->opcode == ZEND_PRE_INC) {
+ | EXT_CALL zend_jit_pre_inc_typed_ref, r0
+ } else if (opline->opcode == ZEND_PRE_DEC) {
+ | EXT_CALL zend_jit_pre_dec_typed_ref, r0
+ } else if (opline->opcode == ZEND_POST_INC) {
+ | EXT_CALL zend_jit_post_inc_typed_ref, r0
+ } else if (opline->opcode == ZEND_POST_DEC) {
+ | EXT_CALL zend_jit_post_dec_typed_ref, r0
+ } else {
+ ZEND_ASSERT(0);
+ }
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ zend_jit_check_exception(Dst);
+ | jmp >3
+ |2:
+ }
+
+ if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
+ zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+
+ | ZVAL_COPY_VALUE res_addr, res_use_info, val_addr, op1_info, ZREG_R0, ZREG_R2
+ | TRY_ADDREF op1_info, ah, r2
+ }
+ if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
+ if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
+ | LOAD_ZVAL_ADDR FCARG2a, res_addr
+ | EXT_CALL zend_jit_pre_inc, r0
+ } else {
+ | EXT_CALL increment_function, r0
+ }
+ } else {
+ if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
+ | LOAD_ZVAL_ADDR FCARG2a, res_addr
+ | EXT_CALL zend_jit_pre_dec, r0
+ } else {
+ | EXT_CALL decrement_function, r0
+ }
+ }
+ } else {
+ zend_reg tmp_reg;
+
+ if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
+ | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_DOUBLE, ZREG_R0, ZREG_R2
+ }
+ if (Z_MODE(op1_def_addr) == IS_REG) {
+ tmp_reg = Z_REG(op1_def_addr);
+ } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
+ tmp_reg = Z_REG(op1_addr);
+ } else {
+ tmp_reg = ZREG_XMM0;
+ }
+ | SSE_GET_ZVAL_DVAL tmp_reg, op1_addr
+ if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ | vaddsd xmm(tmp_reg-ZREG_XMM0), xmm(tmp_reg-ZREG_XMM0), qword [->one]
+ } else {
+ | addsd xmm(tmp_reg-ZREG_XMM0), qword [->one]
+ }
+ } else {
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ | vsubsd xmm(tmp_reg-ZREG_XMM0), xmm(tmp_reg-ZREG_XMM0), qword [->one]
+ } else {
+ | subsd xmm(tmp_reg-ZREG_XMM0), qword [->one]
+ }
+ }
+ | SSE_SET_ZVAL_DVAL op1_def_addr, tmp_reg
+ if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
+ opline->result_type != IS_UNUSED) {
+ | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, op1_def_info, ZREG_R0, ZREG_R1
+ | TRY_ADDREF op1_def_info, ah, r1
+ }
+ }
+ | jmp >3
+ |.code
+ }
+ |3:
+ if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
+ return 0;
+ }
+ if (opline->result_type != IS_UNUSED) {
+ if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int zend_jit_math_long_long(dasm_State **Dst,
+ const zend_op_array *op_array,
+ const zend_op *opline,
+ zend_uchar opcode,
+ zend_jit_addr op1_addr,
+ zend_jit_addr op2_addr,
+ zend_jit_addr res_addr,
+ uint32_t res_info,
+ uint32_t res_use_info,
+ int may_overflow)
+{
+ zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
+ zend_reg result_reg;
+
+ if (Z_MODE(res_addr) == IS_REG) {
+ result_reg = Z_REG(res_addr);
+ } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
+ result_reg = Z_REG(op1_addr);
+ } else {
+ result_reg = ZREG_R0;
+ }
+
+ if (opcode == ZEND_MUL &&
+ ((Z_MODE(op2_addr) == IS_CONST_ZVAL &&
+ IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op2_addr))) &&
+ is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr)))) ||
+ (Z_MODE(op1_addr) == IS_CONST_ZVAL &&
+ IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(op1_addr))) &&
+ is_power_of_two(Z_LVAL_P(Z_ZV(op1_addr)))))) {
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ | shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
+ } else {
+ | GET_ZVAL_LVAL result_reg, op2_addr
+ | shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op1_addr)))
+ }
+ } else if (opcode == ZEND_DIV &&
+ (Z_MODE(op2_addr) == IS_CONST_ZVAL &&
+ is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr))))) {
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ | shr Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
+ } else {
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ if (same_ops && opcode != ZEND_DIV) {
+ | LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
+ } else {
+ | LONG_MATH opcode, result_reg, op2_addr
+ }
+ }
+ if (may_overflow) {
+ | jo >1
+ }
+
+ if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
+ | SET_ZVAL_LVAL res_addr, Ra(result_reg)
+ if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
+ if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_LONG
+ }
+ }
+ }
+
+ if (may_overflow) {
+ zend_reg tmp_reg1 = ZREG_XMM0;
+ zend_reg tmp_reg2 = ZREG_XMM1;
+
+ |.cold_code
+ |1:
+
+ do {
+ if ((Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 1) ||
+ (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1)) {
+ if (opcode == ZEND_ADD) {
+ |.if X64
+ | mov64 rax, 0x43e0000000000000
+ | SET_ZVAL_LVAL res_addr, rax
+ |.else
+ | SET_ZVAL_LVAL res_addr, 0
+ | SET_ZVAL_W2 res_addr, 0x41e00000
+ |.endif
+ break;
+ } else if (opcode == ZEND_SUB) {
+ |.if X64
+ | mov64 rax, 0xc3e0000000000000
+ | SET_ZVAL_LVAL res_addr, rax
+ |.else
+ | SET_ZVAL_LVAL res_addr, 0x00200000
+ | SET_ZVAL_W2 res_addr, 0xc1e00000
+ |.endif
+ break;
+ }
+ }
+
+ | SSE_GET_ZVAL_LVAL tmp_reg1, op1_addr
+ | SSE_GET_ZVAL_LVAL tmp_reg2, op2_addr
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ | AVX_MATH_REG opcode, tmp_reg1, tmp_reg1, tmp_reg2
+ } else {
+ | SSE_MATH_REG opcode, tmp_reg1, tmp_reg2
+ }
+ | SSE_SET_ZVAL_DVAL res_addr, tmp_reg1
+ } while (0);
+
+ if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
+ }
+ | jmp >2
+ |.code
+ |2:
+ }
+
+ return 1;
+}
+
+static int zend_jit_math_long_double(dasm_State **Dst,
+ zend_uchar opcode,
+ zend_jit_addr op1_addr,
+ zend_jit_addr op2_addr,
+ zend_jit_addr res_addr,
+ uint32_t res_use_info)
+{
+ zend_reg result_reg =
+ (Z_MODE(res_addr) == IS_REG) ? Z_REG(res_addr) : ZREG_XMM0;
+
+ | SSE_GET_ZVAL_LVAL result_reg, op1_addr
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ | AVX_MATH opcode, result_reg, result_reg, op2_addr
+ } else {
+ | SSE_MATH opcode, result_reg, op2_addr
+ }
+ | SSE_SET_ZVAL_DVAL res_addr, result_reg
+
+ if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
+ if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_math_double_long(dasm_State **Dst,
+ zend_uchar opcode,
+ zend_jit_addr op1_addr,
+ zend_jit_addr op2_addr,
+ zend_jit_addr res_addr,
+ uint32_t res_use_info)
+{
+ zend_reg result_reg;
+
+ if (zend_is_commutative(opcode)) {
+ if (Z_MODE(res_addr) == IS_REG) {
+ result_reg = Z_REG(res_addr);
+ } else {
+ result_reg = ZREG_XMM0;
+ }
+ | SSE_GET_ZVAL_LVAL result_reg, op2_addr
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ | AVX_MATH opcode, result_reg, result_reg, op1_addr
+ } else {
+ | SSE_MATH opcode, result_reg, op1_addr
+ }
+ } else {
+ zend_reg tmp_reg;
+
+ if (Z_MODE(res_addr) == IS_REG) {
+ result_reg = Z_REG(res_addr);
+ tmp_reg = ZREG_XMM0;
+ } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
+ result_reg = Z_REG(op1_addr);
+ tmp_reg = ZREG_XMM0;
+ } else {
+ result_reg = ZREG_XMM0;
+ tmp_reg = ZREG_XMM1;
+ }
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ zend_reg op1_reg;
+
+ if (Z_MODE(op1_addr) == IS_REG) {
+ op1_reg = Z_REG(op1_addr);
+ } else {
+ | SSE_GET_ZVAL_DVAL result_reg, op1_addr
+ op1_reg = result_reg;
+ }
+ | SSE_GET_ZVAL_LVAL tmp_reg, op2_addr
+ | AVX_MATH_REG opcode, result_reg, op1_reg, tmp_reg
+ } else {
+ | SSE_GET_ZVAL_DVAL result_reg, op1_addr
+ | SSE_GET_ZVAL_LVAL tmp_reg, op2_addr
+ | SSE_MATH_REG opcode, result_reg, tmp_reg
+ }
+ }
+ | SSE_SET_ZVAL_DVAL res_addr, result_reg
+
+ if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
+ if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
+ if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_math_double_double(dasm_State **Dst,
+ zend_uchar opcode,
+ zend_jit_addr op1_addr,
+ zend_jit_addr op2_addr,
+ zend_jit_addr res_addr,
+ uint32_t res_use_info)
+{
+ zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
+ zend_reg result_reg;
+
+ if (Z_MODE(res_addr) == IS_REG) {
+ result_reg = Z_REG(res_addr);
+ } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
+ result_reg = Z_REG(op1_addr);
+ } else {
+ result_reg = ZREG_XMM0;
+ }
+
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ zend_reg op1_reg;
+ zend_jit_addr val_addr;
+
+ if (Z_MODE(op1_addr) == IS_REG) {
+ op1_reg = Z_REG(op1_addr);
+ val_addr = op2_addr;
+ } else if (Z_MODE(op2_addr) == IS_REG && zend_is_commutative(opcode)) {
+ op1_reg = Z_REG(op2_addr);
+ val_addr = op1_addr;
+ } else {
+ | SSE_GET_ZVAL_DVAL result_reg, op1_addr
+ op1_reg = result_reg;
+ val_addr = op2_addr;
+ }
+ if ((opcode == ZEND_MUL) &&
+ Z_MODE(val_addr) == IS_CONST_ZVAL && Z_DVAL_P(Z_ZV(val_addr)) == 2.0) {
+ | AVX_MATH_REG ZEND_ADD, result_reg, op1_reg, op1_reg
+ } else {
+ | AVX_MATH opcode, result_reg, op1_reg, val_addr
+ }
+ } else {
+ zend_jit_addr val_addr;
+
+ if (Z_MODE(op1_addr) != IS_REG && Z_MODE(op2_addr) == IS_REG && zend_is_commutative(opcode)) {
+ | SSE_GET_ZVAL_DVAL result_reg, op2_addr
+ val_addr = op1_addr;
+ } else {
+ | SSE_GET_ZVAL_DVAL result_reg, op1_addr
+ val_addr = op2_addr;
+ }
+ if (same_ops) {
+ | SSE_MATH_REG opcode, result_reg, result_reg
+ } else if ((opcode == ZEND_MUL) &&
+ Z_MODE(val_addr) == IS_CONST_ZVAL && Z_DVAL_P(Z_ZV(val_addr)) == 2.0) {
+ | SSE_MATH_REG ZEND_ADD, result_reg, result_reg
+ } else {
+ | SSE_MATH opcode, result_reg, val_addr
+ }
+ }
+ | SSE_SET_ZVAL_DVAL res_addr, result_reg
+
+ if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
+ if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
+ if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_math_helper(dasm_State **Dst,
+ const zend_op *opline,
+ zend_uchar opcode,
+ const zend_op_array *op_array,
+ zend_uchar op1_type,
+ znode_op op1,
+ zend_jit_addr op1_addr,
+ uint32_t op1_info,
+ zend_uchar op2_type,
+ znode_op op2,
+ zend_jit_addr op2_addr,
+ uint32_t op2_info,
+ uint32_t res_var,
+ zend_jit_addr res_addr,
+ uint32_t res_info,
+ uint32_t res_use_info,
+ int may_overflow,
+ int may_throw)
+/* Labels: 1,2,3,4,5,6 */
+{
+ zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
+
+ if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
+ if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
+ if (op1_info & MAY_BE_DOUBLE) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3
+ } else {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6
+ }
+ }
+ if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
+ if (op2_info & MAY_BE_DOUBLE) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >1
+ |.cold_code
+ |1:
+ if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6
+ }
+ if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
+ return 0;
+ }
+ | jmp >5
+ |.code
+ } else {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
+ }
+ }
+ if (!zend_jit_math_long_long(Dst, op_array, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
+ return 0;
+ }
+ if (op1_info & MAY_BE_DOUBLE) {
+ |.cold_code
+ |3:
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6
+ }
+ if (op2_info & MAY_BE_DOUBLE) {
+ if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
+ if (!same_ops) {
+ | IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >1
+ } else {
+ | IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >6
+ }
+ }
+ if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
+ return 0;
+ }
+ | jmp >5
+ }
+ if (!same_ops) {
+ |1:
+ if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
+ }
+ if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
+ return 0;
+ }
+ | jmp >5
+ }
+ |.code
+ }
+ } else if ((op1_info & MAY_BE_DOUBLE) &&
+ !(op1_info & MAY_BE_LONG) &&
+ (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6
+ }
+ if (op2_info & MAY_BE_DOUBLE) {
+ if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
+ if (!same_ops && (op2_info & MAY_BE_LONG)) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >1
+ } else {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6
+ }
+ }
+ if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
+ return 0;
+ }
+ }
+ if (!same_ops && (op2_info & MAY_BE_LONG)) {
+ if (op2_info & MAY_BE_DOUBLE) {
+ |.cold_code
+ }
+ |1:
+ if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
+ }
+ if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
+ return 0;
+ }
+ if (op2_info & MAY_BE_DOUBLE) {
+ | jmp >5
+ |.code
+ }
+ }
+ } else if ((op2_info & MAY_BE_DOUBLE) &&
+ !(op2_info & MAY_BE_LONG) &&
+ (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6
+ }
+ if (op1_info & MAY_BE_DOUBLE) {
+ if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
+ if (!same_ops && (op1_info & MAY_BE_LONG)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >1
+ } else {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6
+ }
+ }
+ if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
+ return 0;
+ }
+ }
+ if (!same_ops && (op1_info & MAY_BE_LONG)) {
+ if (op1_info & MAY_BE_DOUBLE) {
+ |.cold_code
+ }
+ |1:
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6
+ }
+ if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
+ return 0;
+ }
+ if (op1_info & MAY_BE_DOUBLE) {
+ | jmp >5
+ |.code
+ }
+ }
+ }
+
+ |5:
+
+ if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
+ (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
+ if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+ (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ |.cold_code
+ }
+ |6:
+ | SAVE_VALID_OPLINE opline
+ if (Z_MODE(res_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
+ | LOAD_ZVAL_ADDR FCARG1a, real_addr
+ } else if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
+ | LOAD_ZVAL_ADDR FCARG1a, res_addr
+ }
+ if (Z_MODE(op1_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
+ if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
+ return 0;
+ }
+ op1_addr = real_addr;
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op1_addr
+ if (Z_MODE(op2_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
+ if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
+ return 0;
+ }
+ op2_addr = real_addr;
+ }
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op2_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR op2_addr, r0
+ |.endif
+ if (opcode == ZEND_ADD) {
+ | EXT_CALL add_function, r0
+ } else if (opcode == ZEND_SUB) {
+ | EXT_CALL sub_function, r0
+ } else if (opcode == ZEND_MUL) {
+ | EXT_CALL mul_function, r0
+ } else if (opcode == ZEND_DIV) {
+ | EXT_CALL div_function, r0
+ } else {
+ ZEND_ASSERT(0);
+ }
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ | FREE_OP op1_type, op1, op1_info, 0, op_array, opline
+ | FREE_OP op2_type, op2, op2_info, 0, op_array, opline
+ if (may_throw) {
+ zend_jit_check_exception(Dst);
+ }
+ if (Z_MODE(res_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
+ if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) {
+ return 0;
+ }
+ }
+ if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+ (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | jmp <5
+ |.code
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_math(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, zend_bool send_result, int may_overflow, int may_throw)
+{
+ ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
+ ZEND_ASSERT((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+ (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)));
+
+ if (send_result) {
+ if (!reuse_ip) {
+ zend_jit_start_reuse_ip();
+ | // call = EX(call);
+ | mov RX, EX->call
+ }
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
+ }
+
+ if (!zend_jit_math_helper(Dst, opline, opline->opcode, op_array, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->result.var, res_addr, res_info, res_use_info, may_overflow, may_throw)) {
+ return 0;
+ }
+ if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
+ return 0;
+ }
+ return 1;
+}
+
+static int zend_jit_long_math_helper(dasm_State **Dst,
+ const zend_op *opline,
+ zend_uchar opcode,
+ const zend_op_array *op_array,
+ zend_uchar op1_type,
+ znode_op op1,
+ zend_jit_addr op1_addr,
+ uint32_t op1_info,
+ zend_ssa_range *op1_range,
+ zend_uchar op2_type,
+ znode_op op2,
+ zend_jit_addr op2_addr,
+ uint32_t op2_info,
+ zend_ssa_range *op2_range,
+ uint32_t res_var,
+ zend_jit_addr res_addr,
+ uint32_t res_info,
+ uint32_t res_use_info,
+ int may_throw)
+/* Labels: 6 */
+{
+ zend_bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
+ zend_reg result_reg;
+ zval tmp;
+
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6
+ }
+ if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6
+ }
+
+ if (opcode == ZEND_MOD && Z_MODE(op2_addr) == IS_CONST_ZVAL &&
+ op1_range &&
+ op1_range->min >= 0) {
+ zend_long l = Z_LVAL_P(Z_ZV(op2_addr));
+
+ if (zend_long_is_power_of_two(l)) {
+ /* Optimisation for mod of power of 2 */
+ opcode = ZEND_BW_AND;
+ ZVAL_LONG(&tmp, l - 1);
+ op2_addr = ZEND_ADDR_CONST_ZVAL(&tmp);
+ }
+ }
+
+ if (opcode == ZEND_MOD) {
+ result_reg = ZREG_RAX;
+ } else if (Z_MODE(res_addr) == IS_REG) {
+ result_reg = Z_REG(res_addr);
+ } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) {
+ result_reg = Z_REG(op1_addr);
+ } else {
+ result_reg = ZREG_R0;
+ }
+
+ if (opcode == ZEND_SL) {
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
+
+ if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
+ if (EXPECTED(op2_lval > 0)) {
+ | xor Ra(result_reg), Ra(result_reg)
+ } else {
+ | SAVE_VALID_OPLINE opline
+ | jmp ->negative_shift
+ }
+ } else {
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ | shl Ra(result_reg), op2_lval
+ }
+ } else {
+ if (Z_MODE(op2_addr) != IS_REG || Z_REG(op2_addr) != ZREG_RCX) {
+ | GET_ZVAL_LVAL ZREG_RCX, op2_addr
+ }
+ if (!op2_range ||
+ op2_range->min < 0 ||
+ op2_range->max >= SIZEOF_ZEND_LONG * 8) {
+ | cmp r1, (SIZEOF_ZEND_LONG*8)
+ | jae >1
+ |.cold_code
+ |1:
+ | cmp r1, 0
+ | mov Ra(result_reg), 0
+ | jg >1
+ | SAVE_VALID_OPLINE opline
+ | jmp ->negative_shift
+ |.code
+ }
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ | shl Ra(result_reg), cl
+ |1:
+ }
+ } else if (opcode == ZEND_SR) {
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
+
+ if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
+ if (EXPECTED(op2_lval > 0)) {
+ | sar Ra(result_reg), (SIZEOF_ZEND_LONG * 8) - 1
+ } else {
+ | SAVE_VALID_OPLINE opline
+ | jmp ->negative_shift
+ }
+ } else {
+ | sar Ra(result_reg), op2_lval
+ }
+ } else {
+ if (Z_MODE(op2_addr) != IS_REG || Z_REG(op2_addr) != ZREG_RCX) {
+ | GET_ZVAL_LVAL ZREG_RCX, op2_addr
+ }
+ if (!op2_range ||
+ op2_range->min < 0 ||
+ op2_range->max >= SIZEOF_ZEND_LONG * 8) {
+ | cmp r1, (SIZEOF_ZEND_LONG*8)
+ | jae >1
+ |.cold_code
+ |1:
+ | cmp r1, 0
+ | mov r1, (SIZEOF_ZEND_LONG * 8) - 1
+ | jg >1
+ | SAVE_VALID_OPLINE opline
+ | jmp ->negative_shift
+ |.code
+ }
+ |1:
+ | sar Ra(result_reg), cl
+ }
+ } else if (opcode == ZEND_MOD) {
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
+
+ if (op2_lval == 0) {
+ | SAVE_VALID_OPLINE opline
+ | jmp ->mod_by_zero
+ } else if (op2_lval == -1) {
+ | xor Ra(result_reg), Ra(result_reg)
+ } else {
+ result_reg = ZREG_RDX;
+ | GET_ZVAL_LVAL ZREG_RAX, op1_addr
+ | GET_ZVAL_LVAL ZREG_RCX, op2_addr
+ |.if X64
+ | cqo
+ |.else
+ | cdq
+ |.endif
+ | idiv Ra(ZREG_RCX)
+ }
+ } else {
+ if (!op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
+ if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
+ | cmp aword [Ra(Z_REG(op2_addr))+Z_OFFSET(op2_addr)], 0
+ } else if (Z_MODE(op2_addr) == IS_REG) {
+ | test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr))
+ }
+ | jz >1
+ |.cold_code
+ |1:
+ | SAVE_VALID_OPLINE opline
+ | jmp ->mod_by_zero
+ |.code
+ }
+
+ //TODO: add check for -1 ???
+
+ result_reg = ZREG_RDX;
+ | GET_ZVAL_LVAL ZREG_RAX, op1_addr
+ |.if X64
+ | cqo
+ |.else
+ | cdq
+ |.endif
+ if (Z_MODE(op2_addr) == IS_MEM_ZVAL) {
+ | idiv aword [Ra(Z_REG(op2_addr))+Z_OFFSET(op2_addr)]
+ } else if (Z_MODE(op2_addr) == IS_REG) {
+ | idiv Ra(Z_REG(op2_addr))
+ }
+ }
+ } else if (same_ops) {
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ | LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg)
+ } else {
+ | GET_ZVAL_LVAL result_reg, op1_addr
+ | LONG_MATH opcode, result_reg, op2_addr
+ }
+
+ | SET_ZVAL_LVAL res_addr, Ra(result_reg)
+ if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
+ if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) {
+ if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_LONG
+ }
+ }
+ }
+
+ if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
+ (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
+ if ((op1_info & MAY_BE_LONG) &&
+ (op2_info & MAY_BE_LONG)) {
+ |5:
+ |.cold_code
+ }
+ |6:
+ | SAVE_VALID_OPLINE opline
+ if (Z_MODE(res_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
+ | LOAD_ZVAL_ADDR FCARG1a, real_addr
+ } else if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
+ | LOAD_ZVAL_ADDR FCARG1a, res_addr
+ }
+ if (Z_MODE(op1_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
+ if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
+ return 0;
+ }
+ op1_addr = real_addr;
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op1_addr
+ if (Z_MODE(op2_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
+ if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
+ return 0;
+ }
+ op2_addr = real_addr;
+ }
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op2_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR op2_addr, r0
+ |.endif
+ if (opcode == ZEND_BW_OR) {
+ | EXT_CALL bitwise_or_function, r0
+ } else if (opcode == ZEND_BW_AND) {
+ | EXT_CALL bitwise_and_function, r0
+ } else if (opcode == ZEND_BW_XOR) {
+ | EXT_CALL bitwise_xor_function, r0
+ } else if (opcode == ZEND_SL) {
+ | EXT_CALL shift_left_function, r0
+ } else if (opcode == ZEND_SR) {
+ | EXT_CALL shift_right_function, r0
+ } else if (opcode == ZEND_MOD) {
+ | EXT_CALL mod_function, r0
+ } else {
+ ZEND_ASSERT(0);
+ }
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ | FREE_OP op1_type, op1, op1_info, 0, op_array, opline
+ | FREE_OP op2_type, op2, op2_info, 0, op_array, opline
+ if (may_throw) {
+ zend_jit_check_exception(Dst);
+ }
+ if (Z_MODE(res_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
+ if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) {
+ return 0;
+ }
+ }
+ if ((op1_info & MAY_BE_LONG) &&
+ (op2_info & MAY_BE_LONG)) {
+ | jmp <5
+ |.code
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_long_math(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_ssa_range *op1_range, zend_jit_addr op1_addr, uint32_t op2_info, zend_ssa_range *op2_range, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, zend_bool send_result, int may_throw)
+{
+ ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
+ ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
+
+ if (send_result) {
+ if (!reuse_ip) {
+ zend_jit_start_reuse_ip();
+ | // call = EX(call);
+ | mov RX, EX->call
+ }
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
+ }
+
+ if (!zend_jit_long_math_helper(Dst, opline, opline->opcode, op_array,
+ opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
+ opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
+ opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
+ return 0;
+ }
+ if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
+ return 0;
+ }
+ return 1;
+}
+
+static int zend_jit_concat_helper(dasm_State **Dst,
+ const zend_op *opline,
+ const zend_op_array *op_array,
+ zend_uchar op1_type,
+ znode_op op1,
+ zend_jit_addr op1_addr,
+ uint32_t op1_info,
+ zend_uchar op2_type,
+ znode_op op2,
+ zend_jit_addr op2_addr,
+ uint32_t op2_info,
+ zend_jit_addr res_addr,
+ uint32_t res_info,
+ int may_throw)
+{
+#if 1
+ if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
+ if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6
+ }
+ if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >6
+ }
+ if (Z_MODE(op1_addr) == IS_MEM_ZVAL && Z_REG(op1_addr) == Z_REG(res_addr) && Z_OFFSET(op1_addr) == Z_OFFSET(res_addr)) {
+ if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
+ | LOAD_ZVAL_ADDR FCARG1a, res_addr
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ | EXT_CALL zend_jit_fast_assign_concat_helper, r0
+ } else {
+ if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
+ | LOAD_ZVAL_ADDR FCARG1a, res_addr
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op1_addr
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op2_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR op2_addr, r0
+ |.endif
+ | EXT_CALL zend_jit_fast_concat_helper, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ }
+ | FREE_OP op1_type, op1, op1_info, 0, op_array, opline
+ | FREE_OP op2_type, op2, op2_info, 0, op_array, opline
+ |5:
+ }
+ if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
+ (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
+ if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
+ |.cold_code
+ |6:
+ }
+#endif
+ | SAVE_VALID_OPLINE opline
+ if (Z_REG(res_addr) != ZREG_FCARG1a || Z_OFFSET(res_addr) != 0) {
+ | LOAD_ZVAL_ADDR FCARG1a, res_addr
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op1_addr
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op2_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR op2_addr, r0
+ |.endif
+ | EXT_CALL concat_function, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ | FREE_OP op1_type, op1, op1_info, 0, op_array, opline
+ | FREE_OP op2_type, op2, op2_info, 0, op_array, opline
+ if (may_throw) {
+ zend_jit_check_exception(Dst);
+ }
+#if 1
+ if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
+ | jmp <5
+ |.code
+ }
+ }
+#endif
+
+ return 1;
+}
+
+static int zend_jit_concat(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op2_info, uint32_t res_info, zend_bool send_result, int may_throw)
+{
+ zend_jit_addr op1_addr, op2_addr, res_addr;
+
+ ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
+ ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
+
+ op1_addr = OP1_ADDR();
+ op2_addr = OP2_ADDR();
+
+ if (send_result) {
+ if (!reuse_ip) {
+ zend_jit_start_reuse_ip();
+ | // call = EX(call);
+ | mov RX, EX->call
+ }
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
+ } else {
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+ }
+ return zend_jit_concat_helper(Dst, opline, op_array, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, res_info, may_throw);
+}
+
+static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_op *opline, uint32_t type, uint32_t op1_info, uint32_t op2_info, uint32_t found, uint32_t not_found)
+/* Labels: 1,2,3,4,5 */
+{
+ zend_jit_addr op2_addr = OP2_ADDR();
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ if (op2_info & MAY_BE_LONG) {
+ if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
+ | // if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3
+ }
+ | // hval = Z_LVAL_P(dim);
+ | GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
+ if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ zend_long val = Z_LVAL_P(Z_ZV(op2_addr));
+ if (val >= 0 && val < HT_MAX_SIZE) {
+ | // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ | test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
+ | jz >4 // HASH_FIND
+ | // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
+ |.if X64
+ | movsxd r0, dword [FCARG1a + offsetof(zend_array, nNumUsed)]
+ if (val == 0) {
+ | test r0, r0
+ } else {
+ | cmp r0, val
+ }
+ |.else
+ | cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], val
+ |.endif
+ if (type == BP_JIT_IS) {
+ | jbe >9 // NOT_FOUND
+ } else {
+ | jbe >2 // NOT_FOUND
+ }
+ | // _ret = &_ht->arData[_h].val;
+ | mov r0, aword [FCARG1a + offsetof(zend_array, arData)]
+ if (val != 0) {
+ | add r0, val * sizeof(Bucket)
+ }
+ if (type == BP_JIT_IS) {
+ | jmp >5
+ } else {
+ | IF_NOT_Z_TYPE r0, IS_UNDEF, >8
+ }
+ }
+ } else {
+ | // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
+ | test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
+ | jz >4 // HASH_FIND
+ | // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
+ |.if X64
+ | movsxd r0, dword [FCARG1a + offsetof(zend_array, nNumUsed)]
+ | cmp r0, FCARG2a
+ |.else
+ | cmp dword [FCARG1a + offsetof(zend_array, nNumUsed)], FCARG2a
+ |.endif
+ if (type == BP_JIT_IS) {
+ | jbe >9 // NOT_FOUND
+ } else {
+ | jbe >2 // NOT_FOUND
+ }
+ | // _ret = &_ht->arData[_h].val;
+ |.if X64
+ | mov r0, FCARG2a
+ | shl r0, 5
+ |.else
+ | imul r0, FCARG2a, sizeof(Bucket)
+ |.endif
+ | add r0, aword [FCARG1a + offsetof(zend_array, arData)]
+ if (type == BP_JIT_IS) {
+ | jmp >5
+ } else {
+ | IF_NOT_Z_TYPE r0, IS_UNDEF, >8
+ }
+ }
+ }
+ switch (type) {
+ case BP_JIT_IS:
+ if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
+ |4:
+ }
+ | EXT_CALL zend_hash_index_find, r0
+ | test r0, r0
+ | jz >9 // NOT_FOUND
+ if (op2_info & MAY_BE_STRING) {
+ | jmp >5
+ }
+ break;
+ case BP_VAR_R:
+ case BP_VAR_IS:
+ case BP_VAR_UNSET:
+ if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ zend_long val = Z_LVAL_P(Z_ZV(op2_addr));
+ if (val >= 0 && val < HT_MAX_SIZE) {
+ | jmp >2 // NOT_FOUND
+ }
+ } else {
+ | jmp >2 // NOT_FOUND
+ }
+ |4:
+ }
+ | EXT_CALL zend_hash_index_find, r0
+ | test r0, r0
+ | jz >2 // NOT_FOUND
+ |.cold_code
+ |2:
+ switch (type) {
+ case BP_VAR_R:
+ | // zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ | // retval = &EG(uninitialized_zval);
+ | UNDEFINED_OFFSET opline
+ | jmp >9
+ break;
+ case BP_VAR_IS:
+ case BP_VAR_UNSET:
+ | // retval = &EG(uninitialized_zval);
+ | SET_ZVAL_TYPE_INFO res_addr, IS_NULL
+ | jmp >9
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ |.code
+ break;
+ case BP_VAR_RW:
+ |2:
+ | SAVE_VALID_OPLINE opline
+ | // zend_error(E_NOTICE,"Undefined offset: " ZEND_LONG_FMT, hval);
+ | //retval = zend_hash_index_update(ht, hval, &EG(uninitialized_zval));
+ | EXT_CALL zend_jit_fetch_dimension_rw_long_helper, r0
+ if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
+ | jmp >8
+ |4:
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_hash_index_lookup_rw, r0
+ }
+ break;
+ case BP_VAR_W:
+ |2:
+ | //retval = zend_hash_index_add_new(ht, hval, &EG(uninitialized_zval));
+ |.if X64
+ | LOAD_ADDR_ZTS CARG3, executor_globals, uninitialized_zval
+ |.else
+ | sub r4, 12
+ | PUSH_ADDR_ZTS executor_globals, uninitialized_zval, r0
+ |.endif
+ | EXT_CALL zend_hash_index_add_new, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
+ | jmp >8
+ |4:
+ | EXT_CALL zend_jit_hash_index_lookup_w, r0
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+
+ if (type != BP_JIT_IS && (op2_info & MAY_BE_STRING)) {
+ | jmp >8
+ }
+ }
+
+ if (op2_info & MAY_BE_STRING) {
+ |3:
+ if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
+ | // if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >3
+ }
+ | // offset_key = Z_STR_P(dim);
+ | GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
+ | // retval = zend_hash_find(ht, offset_key);
+ switch (type) {
+ case BP_JIT_IS:
+ if (opline->op2_type != IS_CONST) {
+ | cmp byte [FCARG2a + offsetof(zend_string, val)], '9'
+ | jle >1
+ |.cold_code
+ |1:
+ | EXT_CALL zend_jit_symtable_find, r0
+ | jmp >1
+ |.code
+ | EXT_CALL zend_hash_find, r0
+ |1:
+ } else {
+ | EXT_CALL _zend_hash_find_known_hash, r0
+ }
+ | test r0, r0
+ | jz >9 // NOT_FOUND
+ | // if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT))
+ | IF_NOT_Z_TYPE r0, IS_INDIRECT, >1
+ | GET_Z_PTR r0, r0
+ |1:
+ break;
+ case BP_VAR_R:
+ case BP_VAR_IS:
+ case BP_VAR_UNSET:
+ if (opline->op2_type != IS_CONST) {
+ | cmp byte [FCARG2a + offsetof(zend_string, val)], '9'
+ | jle >1
+ |.cold_code
+ |1:
+ | EXT_CALL zend_jit_symtable_find, r0
+ | jmp >1
+ |.code
+ | EXT_CALL zend_hash_find, r0
+ |1:
+ } else {
+ | EXT_CALL _zend_hash_find_known_hash, r0
+ }
+ | test r0, r0
+ | jz >2 // NOT_FOUND
+ | // if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT))
+ | IF_Z_TYPE r0, IS_INDIRECT, >1 // SLOW
+ |.cold_code
+ |1:
+ | // retval = Z_INDIRECT_P(retval);
+ | GET_Z_PTR r0, r0
+ | IF_NOT_Z_TYPE r0, IS_UNDEF, >8
+ |2:
+ switch (type) {
+ case BP_VAR_R:
+ // zend_error(E_NOTICE, "Undefined index: %s", ZSTR_VAL(offset_key));
+ | UNDEFINED_INDEX opline
+ | jmp >9
+ break;
+ case BP_VAR_IS:
+ case BP_VAR_UNSET:
+ | // retval = &EG(uninitialized_zval);
+ | SET_ZVAL_TYPE_INFO res_addr, IS_NULL
+ | jmp >9
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ |.code
+ break;
+ case BP_VAR_RW:
+ | SAVE_VALID_OPLINE opline
+ if (opline->op2_type != IS_CONST) {
+ | EXT_CALL zend_jit_symtable_lookup_rw, r0
+ } else {
+ | EXT_CALL zend_jit_hash_lookup_rw, r0
+ }
+ break;
+ case BP_VAR_W:
+ if (opline->op2_type != IS_CONST) {
+ | EXT_CALL zend_jit_symtable_lookup_w, r0
+ } else {
+ | EXT_CALL zend_jit_hash_lookup_w, r0
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ }
+
+ if (type == BP_JIT_IS && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))) {
+ |5:
+ if (op1_info & MAY_BE_ARRAY_OF_REF) {
+ | ZVAL_DEREF r0, MAY_BE_REF
+ }
+ | cmp byte [r0 + 8], IS_NULL
+ | jle >9 // NOT FOUND
+ }
+
+ if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
+ if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
+ |.cold_code
+ |3:
+ }
+ | SAVE_VALID_OPLINE opline
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ switch (type) {
+ case BP_VAR_R:
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, res_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR res_addr, r0
+ |.endif
+ | EXT_CALL zend_jit_fetch_dim_r_helper, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ | jmp >9
+ break;
+ case BP_JIT_IS:
+ | EXT_CALL zend_jit_fetch_dim_isset_helper, r0
+ | test r0, r0
+ | jne >8
+ | jmp >9
+ break;
+ case BP_VAR_IS:
+ case BP_VAR_UNSET:
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, res_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR res_addr, r0
+ |.endif
+ | EXT_CALL zend_jit_fetch_dim_is_helper, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ | jmp >9
+ break;
+ case BP_VAR_RW:
+ | EXT_CALL zend_jit_fetch_dim_rw_helper, r0
+ | test r0, r0
+ | jne >8
+ | jmp >9
+ break;
+ case BP_VAR_W:
+ | EXT_CALL zend_jit_fetch_dim_w_helper, r0
+ | test r0, r0
+ | jne >8
+ | jmp >9
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) {
+ |.code
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_simple_assign(dasm_State **Dst,
+ const zend_op *opline,
+ const zend_op_array *op_array,
+ zend_jit_addr var_addr,
+ uint32_t var_info,
+ uint32_t var_def_info,
+ zend_uchar val_type,
+ znode_op val,
+ zend_jit_addr val_addr,
+ uint32_t val_info,
+ zend_jit_addr res_addr,
+ int in_cold)
+/* Labels: 1,2,3 */
+{
+ ZEND_ASSERT(Z_MODE(var_addr) == IS_REG || Z_REG(var_addr) != ZREG_R0);
+ if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
+ zval *zv = Z_ZV(val_addr);
+
+ if (!res_addr) {
+ | ZVAL_COPY_CONST var_addr, var_info, var_def_info, zv, r0
+ } else {
+ | ZVAL_COPY_CONST_2 var_addr, res_addr, var_info, var_def_info, zv, r0
+ }
+ if (Z_REFCOUNTED_P(zv)) {
+ if (!res_addr) {
+ | ADDREF_CONST zv, r0
+ } else {
+ | ADDREF_CONST_2 zv, r0
+ }
+ }
+ } else {
+ if (val_info & MAY_BE_UNDEF) {
+ if (in_cold) {
+ | IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >2
+ } else {
+ | IF_ZVAL_TYPE val_addr, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ }
+ | // zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
+ if (Z_REG(var_addr) != ZREG_FP) {
+ | mov aword T1, Ra(Z_REG(var_addr)) // save
+ }
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1d, val.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ if (Z_REG(var_addr) != ZREG_FP) {
+ | mov Ra(Z_REG(var_addr)), aword T1 // restore
+ }
+ | SET_ZVAL_TYPE_INFO var_addr, IS_NULL
+ if (res_addr) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_NULL
+ }
+ | jmp >3
+ if (in_cold) {
+ |2:
+ } else {
+ |.code
+ }
+ }
+ if (val_info & MAY_BE_REF) {
+ if (val_type == IS_CV) {
+ ZEND_ASSERT(Z_REG(var_addr) != ZREG_R2);
+ | LOAD_ZVAL_ADDR r2, val_addr
+ | ZVAL_DEREF r2, val_info
+ val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R2, 0);
+ } else {
+ zend_jit_addr ref_addr;
+
+ if (in_cold) {
+ | IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, >1
+ } else {
+ | IF_ZVAL_TYPE val_addr, IS_REFERENCE, >1
+ |.cold_code
+ |1:
+ }
+ | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
+ | GET_ZVAL_PTR r2, val_addr
+ | GC_DELREF r2
+ | // ZVAL_COPY_VALUE(return_value, &ref->value);
+ ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R2, 8);
+ if (!res_addr) {
+ | ZVAL_COPY_VALUE var_addr, var_info, ref_addr, val_info, ZREG_R2, ZREG_R0
+ } else {
+ | ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, ref_addr, val_info, ZREG_R2, ZREG_R0
+ }
+ | je >2
+ | IF_NOT_REFCOUNTED dh, >3
+ if (!res_addr) {
+ | GC_ADDREF r0
+ } else {
+ | add dword [r0], 2
+ }
+ | jmp >3
+ |2:
+ if (res_addr) {
+ | IF_NOT_REFCOUNTED dh, >2
+ | GC_ADDREF r0
+ |2:
+ }
+ | EFREE_24 aword [Ra(Z_REG(val_addr))+Z_OFFSET(val_addr)], op_array, opline
+ | jmp >3
+ if (in_cold) {
+ |1:
+ } else {
+ |.code
+ }
+ }
+ }
+
+ if (!res_addr) {
+ | ZVAL_COPY_VALUE var_addr, var_info, val_addr, val_info, ZREG_R2, ZREG_R0
+ } else {
+ | ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, val_addr, val_info, ZREG_R2, ZREG_R0
+ }
+
+ if (val_type == IS_CV) {
+ if (!res_addr) {
+ | TRY_ADDREF val_info, dh, r0
+ } else {
+ | TRY_ADDREF_2 val_info, dh, r0
+ }
+ } else {
+ if (res_addr) {
+ | TRY_ADDREF val_info, dh, r0
+ }
+ }
+ |3:
+ }
+ return 1;
+}
+
+static int zend_jit_assign_to_variable(dasm_State **Dst,
+ const zend_op *opline,
+ const zend_op_array *op_array,
+ zend_jit_addr var_addr,
+ uint32_t var_info,
+ uint32_t var_def_info,
+ zend_uchar val_type,
+ znode_op val,
+ zend_jit_addr val_addr,
+ uint32_t val_info,
+ zend_jit_addr res_addr)
+/* Labels: 1,2,3,4,5,8 */
+{
+ //ZEND_ASSERT(Z_MODE(var_addr) == IS_MEM_ZVAL);
+ if (var_info & MAY_BE_REF) {
+ if (Z_MODE(var_addr) != IS_REG || Z_REG(var_addr) != ZREG_FCARG1a) {
+ | LOAD_ZVAL_ADDR FCARG1a, var_addr
+ var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ }
+ | // if (Z_ISREF_P(variable_ptr)) {
+ | IF_NOT_Z_TYPE, FCARG1a, IS_REFERENCE, >1
+ | // if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) {
+ | GET_Z_PTR FCARG1a, FCARG1a
+ | cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
+ | jnz >2
+ | add FCARG1a, offsetof(zend_reference, val)
+ |.cold_code
+ |2:
+ | LOAD_ZVAL_ADDR FCARG2a, val_addr
+ | SAVE_VALID_OPLINE opline
+ if (val_type == IS_CONST) {
+ | EXT_CALL zend_jit_assign_const_to_typed_ref, r0
+ } else if (val_type == IS_TMP_VAR) {
+ | EXT_CALL zend_jit_assign_tmp_to_typed_ref, r0
+ } else if (val_type == IS_VAR) {
+ | EXT_CALL zend_jit_assign_var_to_typed_ref, r0
+ } else if (val_type == IS_CV) {
+ | EXT_CALL zend_jit_assign_cv_to_typed_ref, r0
+ } else {
+ ZEND_ASSERT(0);
+ }
+ | jmp >8
+ |.code
+ |1:
+ }
+ if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+ int in_cold = 0;
+
+ ZEND_ASSERT(Z_REG(var_addr) != ZREG_R0);
+ if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ | IF_ZVAL_REFCOUNTED var_addr, >1
+ |.cold_code
+ |1:
+ in_cold = 1;
+ }
+ | // TODO: support for object->set
+ | // TODO: support for assignment to itself
+ | GET_ZVAL_PTR r0, var_addr
+ | GC_DELREF r0
+ if (RC_MAY_BE_1(var_info)) {
+ if (RC_MAY_BE_N(var_info)) {
+ | jnz >4
+ }
+ | mov aword T1, r0 // save
+ if (!zend_jit_simple_assign(Dst, opline, op_array, var_addr, var_info, var_def_info, val_type, val, val_addr, val_info, res_addr, in_cold)) {
+ return 0;
+ }
+ | mov FCARG1a, aword T1 // restore
+ if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
+ | cmp dword [FCARG1a], 0
+ | jnz >8
+ }
+ | ZVAL_DTOR_FUNC var_info, opline
+ | jmp >8
+ |4:
+ }
+ if (RC_MAY_BE_N(var_info)) {
+ if (Z_REG(var_addr) == ZREG_FP) {
+ | GET_ZVAL_PTR FCARG1a, var_addr
+ | IF_GC_MAY_NOT_LEAK FCARG1a, eax, >5
+ } else if (Z_REG(var_addr) != ZREG_FCARG1a) {
+ | GET_ZVAL_PTR FCARG1a, var_addr
+ | IF_GC_MAY_NOT_LEAK FCARG1a, eax, >5
+ | mov T1, Ra(Z_REG(var_addr)) // save
+ } else {
+ | GET_ZVAL_PTR r0, var_addr
+ | IF_GC_MAY_NOT_LEAK r0, eax, >5
+ | mov T1, Ra(Z_REG(var_addr)) // save
+ | GET_ZVAL_PTR FCARG1a, var_addr
+ }
+ | EXT_CALL gc_possible_root, r0
+ if (Z_REG(var_addr) != ZREG_FP) {
+ | mov Ra(Z_REG(var_addr)), T1 // restore
+ }
+ if (in_cold) {
+ | jmp >5
+ |.code
+ }
+ } else if (in_cold) {
+ ZEND_ASSERT(RC_MAY_BE_1(var_info));
+ |.code
+ }
+ |5:
+ }
+
+ if (!zend_jit_simple_assign(Dst, opline, op_array, var_addr, var_info, var_def_info, val_type, val, val_addr, val_info, res_addr, 0)) {
+ return 0;
+ }
+ |8:
+
+ return 1;
+}
+
+static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op2_info, uint32_t val_info, int may_throw)
+{
+ zend_jit_addr op1_addr, op2_addr, op3_addr, res_addr;
+
+ ZEND_ASSERT(opline->op1_type == IS_CV);
+
+ op1_addr = OP1_ADDR();
+ op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
+ op3_addr = OP1_DATA_ADDR();
+ if (opline->result_type == IS_UNUSED) {
+ res_addr = 0;
+ } else {
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+ }
+
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | IF_NOT_Z_TYPE FCARG1a, IS_REFERENCE, >1
+ | GET_Z_PTR FCARG2a, FCARG1a
+ | IF_NOT_TYPE byte [FCARG2a + offsetof(zend_reference, val) + offsetof(zval, u1.v.type)], IS_ARRAY, >2
+ | lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
+ | jmp >3
+ |.cold_code
+ |2:
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_prepare_assign_dim_ref, r0
+ | test r0, r0
+ | jz ->exception_handler_undef
+ | mov FCARG1a, r0
+ | jmp >1
+ |.code
+ |1:
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ }
+
+ if (op1_info & MAY_BE_ARRAY) {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
+ }
+ |3:
+ | SEPARATE_ARRAY op1_addr, op1_info, 1
+ } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
+ | CMP_ZVAL_TYPE op1_addr, IS_FALSE
+ | jg >7
+ }
+ | // ZVAL_ARR(container, zend_new_array(8));
+ if (Z_REG(op1_addr) != ZREG_FP) {
+ | mov T1, Ra(Z_REG(op1_addr)) // save
+ }
+ | EXT_CALL _zend_new_array_0, r0
+ if (Z_REG(op1_addr) != ZREG_FP) {
+ | mov Ra(Z_REG(op1_addr)), T1 // restore
+ }
+ | SET_ZVAL_LVAL op1_addr, r0
+ | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX
+ | mov FCARG1a, r0
+ }
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
+ |6:
+ if (opline->op2_type == IS_UNUSED) {
+ uint32_t var_info = MAY_BE_NULL;
+ zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+
+ | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
+ | LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
+ | EXT_CALL zend_hash_next_index_insert, r0
+ | // if (UNEXPECTED(!var_ptr)) {
+ | test r0, r0
+ | jz >1
+ |.cold_code
+ |1:
+ | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
+ | CANNOT_ADD_ELEMENT opline
+ | //ZEND_VM_C_GOTO(assign_dim_op_ret_null);
+ | jmp >9
+ |.code
+ | mov FCARG1a, r0
+
+ if (!zend_jit_simple_assign(Dst, opline, op_array, var_addr, var_info, -1, (opline+1)->op1_type, (opline+1)->op1, op3_addr, val_info, res_addr, 0)) {
+ return 0;
+ }
+ } else {
+ uint32_t var_info = zend_array_element_type(op1_info, 0, 0);
+ zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_W, op1_info, op2_info, 8, 8)) {
+ return 0;
+ }
+
+ |8:
+ | mov FCARG1a, r0
+
+ if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
+ var_info |= MAY_BE_REF;
+ }
+ | // value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
+ if (!zend_jit_assign_to_variable(Dst, opline, op_array, var_addr, var_info, -1, (opline+1)->op1_type, (opline+1)->op1, op3_addr, val_info, res_addr)) {
+ return 0;
+ }
+ }
+ }
+
+ if (((op1_info & MAY_BE_ARRAY) &&
+ (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE))) ||
+ (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)))) {
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
+ |.cold_code
+ |7:
+ }
+
+ if ((op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) &&
+ (op1_info & MAY_BE_ARRAY)) {
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
+ | CMP_ZVAL_TYPE op1_addr, IS_FALSE
+ | jg >2
+ }
+ | // ZVAL_ARR(container, zend_new_array(8));
+ if (Z_REG(op1_addr) != ZREG_FP) {
+ | mov T1, Ra(Z_REG(op1_addr)) // save
+ }
+ | EXT_CALL _zend_new_array_0, r0
+ if (Z_REG(op1_addr) != ZREG_FP) {
+ | mov Ra(Z_REG(op1_addr)), T1 // restore
+ }
+ | SET_ZVAL_LVAL op1_addr, r0
+ | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX
+ | mov FCARG1a, r0
+ | // ZEND_VM_C_GOTO(assign_dim_op_new_array);
+ | jmp <6
+ |2:
+ }
+
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
+ | SAVE_VALID_OPLINE opline
+ if (Z_REG(op1_addr) != ZREG_FCARG1a) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ if (opline->op2_type == IS_UNUSED) {
+ | xor FCARG2a, FCARG2a
+ } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
+ ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
+ | LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
+ } else {
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ }
+ |.if not(X64)
+ | sub r4, 8
+ |.endif
+ if (opline->result_type == IS_UNUSED) {
+ |.if X64
+ | xor CARG4, CARG4
+ |.else
+ | push 0
+ |.endif
+ } else {
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG4, res_addr
+ |.else
+ | PUSH_ZVAL_ADDR res_addr, r0
+ |.endif
+ }
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op3_addr
+ |.else
+ | PUSH_ZVAL_ADDR op3_addr, r0
+ |.endif
+ | EXT_CALL zend_jit_assign_dim_helper, r0
+ |.if not(X64)
+ | add r4, 8
+ |.endif
+
+#ifdef ZEND_JIT_USE_RC_INFERENCE
+ if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
+ /* ASSIGN_DIM may increase refcount of the value */
+ val_info |= MAY_BE_RCN;
+ }
+#endif
+
+ | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, op_array, opline
+ }
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
+ | jmp >9 // END
+ }
+ |.code
+ }
+ }
+
+#ifdef ZEND_JIT_USE_RC_INFERENCE
+ if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
+ /* ASSIGN_DIM may increase refcount of the key */
+ op2_info |= MAY_BE_RCN;
+ }
+#endif
+
+ |9:
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
+
+ if (may_throw) {
+ zend_jit_check_exception(Dst);
+ }
+
+ return 1;
+}
+
+static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op1_def_info, uint32_t op2_info, uint32_t op1_data_info, zend_ssa_range *op1_data_range, int may_throw)
+{
+ zend_jit_addr op1_addr, op2_addr, op3_addr, var_addr;
+
+ ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
+
+ op1_addr = OP1_ADDR();
+ op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0;
+ op3_addr = OP1_DATA_ADDR();
+
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | IF_NOT_Z_TYPE FCARG1a, IS_REFERENCE, >1
+ | GET_Z_PTR FCARG2a, FCARG1a
+ | IF_NOT_TYPE byte [FCARG2a + offsetof(zend_reference, val) + offsetof(zval, u1.v.type)], IS_ARRAY, >2
+ | lea FCARG1a, [FCARG2a + offsetof(zend_reference, val)]
+ | jmp >3
+ |.cold_code
+ |2:
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_prepare_assign_dim_ref, r0
+ | test r0, r0
+ | jz ->exception_handler_undef
+ | mov FCARG1a, r0
+ | jmp >1
+ |.code
+ |1:
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ }
+
+ if (op1_info & MAY_BE_ARRAY) {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
+ }
+ |3:
+ | SEPARATE_ARRAY op1_addr, op1_info, 1
+ }
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
+ if (op1_info & MAY_BE_ARRAY) {
+ |.cold_code
+ |7:
+ }
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
+ | CMP_ZVAL_TYPE op1_addr, IS_FALSE
+ | jg >7
+ }
+ if (op1_info & MAY_BE_UNDEF) {
+ if (op1_info & (MAY_BE_NULL|MAY_BE_FALSE)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
+ }
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1a, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ |1:
+ }
+ | // ZVAL_ARR(container, zend_new_array(8));
+ if (Z_REG(op1_addr) != ZREG_FP) {
+ | mov T1, Ra(Z_REG(op1_addr)) // save
+ }
+ | EXT_CALL _zend_new_array_0, r0
+ if (Z_REG(op1_addr) != ZREG_FP) {
+ | mov Ra(Z_REG(op1_addr)), T1 // restore
+ }
+ | SET_ZVAL_LVAL op1_addr, r0
+ | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX
+ | mov FCARG1a, r0
+ if (op1_info & MAY_BE_ARRAY) {
+ | jmp >1
+ |.code
+ |1:
+ }
+ }
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
+ uint32_t var_info;
+ uint32_t var_def_info = zend_array_element_type(op1_def_info, 1, 0);
+
+ |6:
+ if (opline->op2_type == IS_UNUSED) {
+ var_info = MAY_BE_NULL;
+
+ | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
+ | LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
+ | EXT_CALL zend_hash_next_index_insert, r0
+ | // if (UNEXPECTED(!var_ptr)) {
+ | test r0, r0
+ | jz >1
+ |.cold_code
+ |1:
+ | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
+ | CANNOT_ADD_ELEMENT opline
+ | //ZEND_VM_C_GOTO(assign_dim_op_ret_null);
+ | jmp >9
+ |.code
+ | mov FCARG1a, r0
+ } else {
+ var_info = zend_array_element_type(op1_info, 0, 0);
+ if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
+ var_info |= MAY_BE_REF;
+ }
+
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_RW, op1_info, op2_info, 8, 8)) {
+ return 0;
+ }
+
+ |8:
+ | mov FCARG1a, r0
+ if (op1_info & (MAY_BE_ARRAY_OF_REF)) {
+ binary_op_type binary_op = get_binary_op(opline->extended_value);
+ | IF_NOT_Z_TYPE, FCARG1a, IS_REFERENCE, >1
+ | GET_Z_PTR FCARG1a, FCARG1a
+ | cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
+ | jnz >2
+ | add FCARG1a, offsetof(zend_reference, val)
+ |.cold_code
+ |2:
+ | LOAD_ZVAL_ADDR FCARG2a, op3_addr
+ |.if X64
+ | LOAD_ADDR CARG3, binary_op
+ |.else
+ | sub r4, 12
+ | PUSH_ADDR binary_op, r0
+ |.endif
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_assign_op_to_typed_ref, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ zend_jit_check_exception(Dst);
+ | jmp >9
+ |.code
+ |1:
+ }
+ }
+
+ var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ switch (opline->extended_value) {
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ case ZEND_DIV:
+ if (!zend_jit_math_helper(Dst, opline, opline->extended_value, op_array, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, 0, var_addr, var_def_info, var_info,
+ 1 /* may overflow */, may_throw)) {
+ return 0;
+ }
+ break;
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ case ZEND_SL:
+ case ZEND_SR:
+ case ZEND_MOD:
+ if (!zend_jit_long_math_helper(Dst, opline, opline->extended_value, op_array,
+ IS_CV, opline->op1, var_addr, var_info, NULL,
+ (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info,
+ op1_data_range,
+ 0, var_addr, op1_def_info, var_info, may_throw)) {
+ return 0;
+ }
+ break;
+ case ZEND_CONCAT:
+ if (!zend_jit_concat_helper(Dst, opline, op_array, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, var_addr, op1_def_info,
+ may_throw)) {
+ return 0;
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ }
+
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY))) {
+ binary_op_type binary_op;
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
+ |.cold_code
+ |7:
+ }
+
+ | SAVE_VALID_OPLINE opline
+ if (Z_REG(op1_addr) != ZREG_FCARG1a) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ if (opline->op2_type == IS_UNUSED) {
+ | xor FCARG2a, FCARG2a
+ } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
+ ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
+ | LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
+ } else {
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ }
+ binary_op = get_binary_op(opline->extended_value);
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op3_addr
+ | LOAD_ADDR CARG4, binary_op
+ |.else
+ | sub r4, 8
+ | PUSH_ADDR binary_op, r0
+ | PUSH_ZVAL_ADDR op3_addr, r0
+ |.endif
+ | EXT_CALL zend_jit_assign_dim_op_helper, r0
+ |.if not(X64)
+ | add r4, 8
+ |.endif
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY)) {
+ | jmp >9 // END
+ |.code
+ }
+ }
+
+ |9:
+
+ return 1;
+}
+
+static int zend_jit_assign_op(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op1_def_info, zend_ssa_range *op1_range, uint32_t op2_info, zend_ssa_range *op2_range, int may_overflow, int may_throw)
+{
+ zend_jit_addr op1_addr, op2_addr;
+
+ ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
+ ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
+
+ op1_addr = OP1_ADDR();
+ op2_addr = OP2_ADDR();
+
+ if (op1_info & MAY_BE_REF) {
+ binary_op_type binary_op = get_binary_op(opline->extended_value);
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | IF_NOT_Z_TYPE, FCARG1a, IS_REFERENCE, >1
+ | GET_Z_PTR FCARG1a, FCARG1a
+ | cmp aword [FCARG1a + offsetof(zend_reference, sources.ptr)], 0
+ | jnz >2
+ | add FCARG1a, offsetof(zend_reference, val)
+ |.cold_code
+ |2:
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ |.if X64
+ | LOAD_ADDR CARG3, binary_op
+ |.else
+ | sub r4, 12
+ | PUSH_ADDR binary_op, r0
+ |.endif
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_assign_op_to_typed_ref, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ zend_jit_check_exception(Dst);
+ | jmp >9
+ |.code
+ |1:
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ }
+
+ int result;
+ switch (opline->extended_value) {
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ case ZEND_DIV:
+ result = zend_jit_math_helper(Dst, opline, opline->extended_value, op_array, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_addr, op1_def_info, op1_info, may_overflow, may_throw);
+ break;
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ case ZEND_SL:
+ case ZEND_SR:
+ case ZEND_MOD:
+ result = zend_jit_long_math_helper(Dst, opline, opline->extended_value, op_array,
+ opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
+ opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
+ opline->op1.var, op1_addr, op1_def_info, op1_info, may_throw);
+ break;
+ case ZEND_CONCAT:
+ result = zend_jit_concat_helper(Dst, opline, op_array, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_addr, op1_def_info, may_throw);
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ |9:
+ return result;
+}
+
+static int zend_jit_cmp_long_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ zend_bool swap = 0;
+
+ if (Z_MODE(op1_addr) == IS_REG) {
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
+ | test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
+ } else {
+ | LONG_OP cmp, Z_REG(op1_addr), op2_addr
+ }
+ } else if (Z_MODE(op2_addr) == IS_REG) {
+ if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) {
+ | test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr))
+ } else {
+ | LONG_OP cmp, Z_REG(op2_addr), op1_addr
+ }
+ swap = 1;
+ } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL) {
+ | LONG_OP_WITH_CONST cmp, op2_addr, Z_LVAL_P(Z_ZV(op1_addr))
+ swap = 1;
+ } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_MODE(op1_addr) != IS_CONST_ZVAL) {
+ | LONG_OP_WITH_CONST cmp, op1_addr, Z_LVAL_P(Z_ZV(op2_addr))
+ } else {
+ | GET_ZVAL_LVAL ZREG_R0, op1_addr
+ if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) {
+ | test r0, r0
+ } else {
+ | LONG_OP cmp, ZREG_R0, op2_addr
+ }
+ }
+
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ_EX ||
+ smart_branch_opcode == ZEND_JMPNZ_EX) {
+
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | sete al
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | setne al
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | setg al
+ } else {
+ | setl al
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | setge al
+ } else {
+ | setle al
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | movzx eax, al
+ | lea eax, [eax + 2]
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ if (smart_branch_opcode == ZEND_JMPZ ||
+ smart_branch_opcode == ZEND_JMPZ_EX) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | jne => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | je => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | jle => target_label
+ } else {
+ | jge => target_label
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | jl => target_label
+ } else {
+ | jg => target_label
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else if (smart_branch_opcode == ZEND_JMPNZ ||
+ smart_branch_opcode == ZEND_JMPNZ_EX) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | je => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | jne => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | jg => target_label
+ } else {
+ | jl => target_label
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | jge => target_label
+ } else {
+ | jle => target_label
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | jne => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | je => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | jle => target_label
+ } else {
+ | jge => target_label
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | jl => target_label
+ } else {
+ | jg => target_label
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | jmp => target_label2
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | sete al
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | setne al
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | setg al
+ } else {
+ | setl al
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | setge al
+ } else {
+ | setle al
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | movzx eax, al
+ | add eax, 2
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+
+ return 1;
+}
+
+static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, zend_bool swap, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | jne => target_label
+ | jp => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | jp >1
+ | je => target_label
+ |1:
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | jbe => target_label
+ } else {
+ | jae => target_label
+ | jp => target_label
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | jb => target_label
+ } else {
+ | ja => target_label
+ | jp => target_label
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | jp >1
+ | je => target_label
+ |1:
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | jne => target_label
+ | jp => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | ja => target_label
+ } else {
+ | jp >1
+ | jb => target_label
+ |1:
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | jae => target_label
+ } else {
+ | jp >1
+ | jbe => target_label
+ |1:
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | jne => target_label
+ | jp => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | jp => target_label2
+ | je => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | jbe => target_label
+ } else {
+ | jae => target_label
+ | jp => target_label
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | jb => target_label
+ } else {
+ | ja => target_label
+ | jp => target_label
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | jmp => target_label2
+ } else if (smart_branch_opcode == ZEND_JMPZ_EX) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ | jne => target_label
+ | jp => target_label
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | jp >1
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ | je => target_label
+ |1:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ | jbe => target_label
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ | jae => target_label
+ | jp => target_label
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ | jb => target_label
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ | ja => target_label
+ | jp => target_label
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else if (smart_branch_opcode == ZEND_JMPNZ_EX) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | jp >1
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ | je => target_label
+ |1:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ | jne => target_label
+ | jp => target_label
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | seta al
+ | movzx eax, al
+ | lea eax, [eax + 2]
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ | ja => target_label
+ } else {
+ | jp >1
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ | jb => target_label
+ |1:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | setae al
+ | movzx eax, al
+ | lea eax, [eax + 2]
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ | jae => target_label
+ } else {
+ | jp >1
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ | jbe => target_label
+ |1:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_CASE:
+ | jp >1
+ | mov eax, IS_TRUE
+ | je >2
+ |1:
+ | mov eax, IS_FALSE
+ |2:
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ | jp >1
+ | mov eax, IS_FALSE
+ | je >2
+ |1:
+ | mov eax, IS_TRUE
+ |2:
+ break;
+ case ZEND_IS_SMALLER:
+ if (swap) {
+ | seta al
+ | movzx eax, al
+ | add eax, 2
+ } else {
+ | jp >1
+ | mov eax, IS_TRUE
+ | jb >2
+ |1:
+ | mov eax, IS_FALSE
+ |2:
+ }
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ if (swap) {
+ | setae al
+ | movzx eax, al
+ | add eax, 2
+ } else {
+ | jp >1
+ | mov eax, IS_TRUE
+ | jbe >2
+ |1:
+ | mov eax, IS_FALSE
+ |2:
+ }
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+
+ return 1;
+}
+
+static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ zend_reg tmp_reg = ZREG_XMM0;
+
+ | SSE_GET_ZVAL_LVAL tmp_reg, op1_addr
+ | SSE_AVX_OP ucomisd, vucomisd, tmp_reg, op2_addr
+
+ return zend_jit_cmp_double_common(Dst, opline, res_addr, 0, smart_branch_opcode, target_label, target_label2);
+}
+
+static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ zend_reg tmp_reg = ZREG_XMM0;
+
+ | SSE_GET_ZVAL_LVAL tmp_reg, op2_addr
+ | SSE_AVX_OP ucomisd, vucomisd, tmp_reg, op1_addr
+
+ return zend_jit_cmp_double_common(Dst, opline, res_addr, /* swap */ 1, smart_branch_opcode, target_label, target_label2);
+}
+
+static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ zend_bool swap = 0;
+
+ if (Z_MODE(op1_addr) == IS_REG) {
+ | SSE_AVX_OP ucomisd, vucomisd, Z_REG(op1_addr), op2_addr
+ } else if (Z_MODE(op2_addr) == IS_REG) {
+ | SSE_AVX_OP ucomisd, vucomisd, Z_REG(op2_addr), op1_addr
+ swap = 1;
+ } else {
+ zend_reg tmp_reg = ZREG_XMM0;
+
+ | SSE_GET_ZVAL_DVAL tmp_reg, op1_addr
+ | SSE_AVX_OP ucomisd, vucomisd, tmp_reg, op2_addr
+ }
+
+ return zend_jit_cmp_double_common(Dst, opline, res_addr, swap, smart_branch_opcode, target_label, target_label2);
+}
+
+static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ | LONG_OP_WITH_CONST cmp, res_addr, Z_L(0)
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ_EX ||
+ smart_branch_opcode == ZEND_JMPNZ_EX) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_CASE:
+ | sete al
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ | setne al
+ break;
+ case ZEND_IS_SMALLER:
+ | setl al
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ | setle al
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | movzx eax, al
+ | lea eax, [eax + 2]
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ if (smart_branch_opcode == ZEND_JMPZ ||
+ smart_branch_opcode == ZEND_JMPZ_EX) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_CASE:
+ | jne => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ | je => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ | jge => target_label
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ | jg => target_label
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else if (smart_branch_opcode == ZEND_JMPNZ ||
+ smart_branch_opcode == ZEND_JMPNZ_EX) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_CASE:
+ | je => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ | jne => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ | jl => target_label
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ | jle => target_label
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_CASE:
+ | jne => target_label
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ | je => target_label
+ break;
+ case ZEND_IS_SMALLER:
+ | jge => target_label
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ | jg => target_label
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | jmp => target_label2
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ switch (opline->opcode) {
+ case ZEND_IS_EQUAL:
+ case ZEND_CASE:
+ | sete al
+ break;
+ case ZEND_IS_NOT_EQUAL:
+ | setne al
+ break;
+ case ZEND_IS_SMALLER:
+ | setl al
+ break;
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ | setle al
+ break;
+ default:
+ ZEND_ASSERT(0);
+ }
+ | movzx eax, al
+ | add eax, 2
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+
+ return 1;
+}
+
+static int zend_jit_cmp(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ zend_bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var);
+ zend_bool has_slow;
+
+ has_slow =
+ (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+ (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
+ ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
+ (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
+
+ if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
+ if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
+ if (op1_info & MAY_BE_DOUBLE) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >4
+ } else {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9
+ }
+ }
+ if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
+ if (op2_info & MAY_BE_DOUBLE) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3
+ |.cold_code
+ |3:
+ if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
+ }
+ if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ | jmp >6
+ |.code
+ } else {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
+ }
+ }
+ if (!zend_jit_cmp_long_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ if (op1_info & MAY_BE_DOUBLE) {
+ |.cold_code
+ |4:
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9
+ }
+ if (op2_info & MAY_BE_DOUBLE) {
+ if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
+ if (!same_ops) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >5
+ } else {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
+ }
+ }
+ if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ | jmp >6
+ }
+ if (!same_ops) {
+ |5:
+ if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
+ }
+ if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ | jmp >6
+ }
+ |.code
+ }
+ } else if ((op1_info & MAY_BE_DOUBLE) &&
+ !(op1_info & MAY_BE_LONG) &&
+ (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9
+ }
+ if (op2_info & MAY_BE_DOUBLE) {
+ if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
+ if (!same_ops && (op2_info & MAY_BE_LONG)) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >3
+ } else {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
+ }
+ }
+ if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ }
+ if (!same_ops && (op2_info & MAY_BE_LONG)) {
+ if (op2_info & MAY_BE_DOUBLE) {
+ |.cold_code
+ }
+ |3:
+ if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9
+ }
+ if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ if (op2_info & MAY_BE_DOUBLE) {
+ | jmp >6
+ |.code
+ }
+ }
+ } else if ((op2_info & MAY_BE_DOUBLE) &&
+ !(op2_info & MAY_BE_LONG) &&
+ (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
+ if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9
+ }
+ if (op1_info & MAY_BE_DOUBLE) {
+ if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
+ if (!same_ops && (op1_info & MAY_BE_LONG)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >3
+ } else {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9
+ }
+ }
+ if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ }
+ if (!same_ops && (op1_info & MAY_BE_LONG)) {
+ if (op1_info & MAY_BE_DOUBLE) {
+ |.cold_code
+ }
+ |3:
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9
+ }
+ if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ if (op1_info & MAY_BE_DOUBLE) {
+ | jmp >6
+ |.code
+ }
+ }
+ }
+
+ if (has_slow ||
+ (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
+ (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
+ if (has_slow) {
+ |.cold_code
+ |9:
+ }
+ | SAVE_VALID_OPLINE opline
+ if (Z_MODE(op1_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
+ if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
+ return 0;
+ }
+ op1_addr = real_addr;
+ }
+ if (Z_MODE(op2_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
+ if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
+ return 0;
+ }
+ op2_addr = real_addr;
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op1_addr
+ if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
+ | IF_NOT_Z_TYPE FCARG2a, IS_UNDEF, >1
+ | mov FCARG1a, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ | LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
+ |1:
+ }
+ if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1
+ | mov T1, FCARG2a // save
+ | mov FCARG1a, opline->op2.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ | mov FCARG2a, T1 // restore
+ |.if X64
+ | LOAD_ADDR_ZTS CARG3, executor_globals, uninitialized_zval
+ |.else
+ | sub r4, 12
+ | PUSH_ADDR_ZTS executor_globals, uninitialized_zval, r0
+ |.endif
+ | jmp >2
+ |1:
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op2_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR op2_addr, r0
+ |.endif
+ |2:
+ } else {
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, op2_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR op2_addr, r0
+ |.endif
+ }
+ | LOAD_ZVAL_ADDR FCARG1a, res_addr
+ | EXT_CALL compare_function, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ if (opline->opcode != ZEND_CASE) {
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
+ }
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
+ if (may_throw) {
+ zend_jit_check_exception_undef_result(Dst, opline);
+ }
+ if (!zend_jit_cmp_slow(Dst, opline, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ if (has_slow) {
+ | jmp >6
+ |.code
+ }
+ }
+
+ |6:
+
+ return 1;
+}
+
+static int zend_jit_identical(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr, int may_throw, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ uint32_t identical_label = (uint32_t)-1;
+ uint32_t not_identical_label = (uint32_t)-1;
+
+ if (smart_branch_opcode) {
+ if (opline->opcode == ZEND_IS_IDENTICAL) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ not_identical_label = target_label;
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ identical_label = target_label;
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ not_identical_label = target_label;
+ identical_label = target_label2;
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ identical_label = target_label;
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ not_identical_label = target_label;
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ identical_label = target_label;
+ not_identical_label = target_label2;
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ }
+
+ if ((op1_info & MAY_BE_UNDEF) && (op2_info & MAY_BE_UNDEF)) {
+ op1_info |= MAY_BE_NULL;
+ op2_info |= MAY_BE_NULL;
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | IF_Z_TYPE FCARG1a, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ | // zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1d, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ if (may_throw) {
+ zend_jit_check_exception_undef_result(Dst, opline);
+ }
+ | LOAD_ADDR_ZTS FCARG1a, executor_globals, uninitialized_zval
+ | jmp >1
+ |.code
+ |1:
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ | IF_Z_TYPE FCARG2a, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ | // zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
+ | SAVE_VALID_OPLINE opline
+ | mov aword T1, FCARG1a // save
+ | mov FCARG1d, opline->op2.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ if (may_throw) {
+ zend_jit_check_exception_undef_result(Dst, opline);
+ }
+ | mov FCARG1a, aword T1 // restore
+ | LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
+ | jmp >1
+ |.code
+ |1:
+ } else if (op1_info & MAY_BE_UNDEF) {
+ op1_info |= MAY_BE_NULL;
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | IF_Z_TYPE FCARG1a, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ | // zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1d, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ if (may_throw) {
+ zend_jit_check_exception_undef_result(Dst, opline);
+ }
+ | LOAD_ADDR_ZTS FCARG1a, executor_globals, uninitialized_zval
+ | jmp >1
+ |.code
+ |1:
+ if (opline->op2_type != IS_CONST) {
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ }
+ } else if (op2_info & MAY_BE_UNDEF) {
+ op2_info |= MAY_BE_NULL;
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ | IF_Z_TYPE FCARG2a, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ | // zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1d, opline->op2.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ if (may_throw) {
+ zend_jit_check_exception_undef_result(Dst, opline);
+ }
+ | LOAD_ADDR_ZTS FCARG2a, executor_globals, uninitialized_zval
+ | jmp >1
+ |.code
+ |1:
+ if (opline->op1_type != IS_CONST) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ } else {
+ if (opline->op1_type != IS_CONST) {
+ if (Z_MODE(op1_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
+ if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) {
+ return 0;
+ }
+ op1_addr = real_addr;
+ }
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ if (opline->op2_type != IS_CONST) {
+ if (Z_MODE(op2_addr) == IS_REG) {
+ zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
+ if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) {
+ return 0;
+ }
+ op2_addr = real_addr;
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ }
+ }
+ if (opline->op1_type & (IS_CV|IS_VAR)) {
+ | ZVAL_DEREF FCARG1a, op1_info
+ }
+ if (opline->op2_type & (IS_CV|IS_VAR)) {
+ | ZVAL_DEREF FCARG2a, op2_info
+ }
+
+ if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
+ if (((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) ||
+ ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) {
+ | SAVE_VALID_OPLINE opline
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 1, op_array, opline
+ }
+ if (smart_branch_opcode) {
+ zend_jit_check_exception_undef_result(Dst, opline);
+ if (not_identical_label != (uint32_t)-1) {
+ | jmp =>not_identical_label
+ }
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_FALSE : IS_TRUE)
+ zend_jit_check_exception(Dst);
+ }
+ } else if (has_concrete_type(op1_info) &&
+ has_concrete_type(op2_info) &&
+ concrete_type(op1_info) == concrete_type(op2_info) &&
+ concrete_type(op1_info) <= IS_TRUE) {
+ if (smart_branch_opcode) {
+ if (identical_label != (uint32_t)-1) {
+ | jmp =>identical_label
+ }
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_TRUE : IS_FALSE)
+ }
+ } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
+ if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
+ if (smart_branch_opcode) {
+ if (identical_label != (uint32_t)-1) {
+ | jmp =>identical_label
+ }
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_TRUE : IS_FALSE)
+ }
+ } else {
+ if (smart_branch_opcode) {
+ if (not_identical_label != (uint32_t)-1) {
+ | jmp =>not_identical_label
+ }
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode == ZEND_IS_IDENTICAL ? IS_FALSE : IS_TRUE)
+ }
+ }
+ } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
+ zval *val = Z_ZV(op1_addr);
+
+ | cmp byte [FCARG2a + offsetof(zval, u1.v.type)], Z_TYPE_P(val)
+ if (smart_branch_opcode) {
+ if (opline->op2_type == IS_VAR && (op2_info & MAY_BE_REF)) {
+ | jne >8
+ | SAVE_VALID_OPLINE opline
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 1, op_array, opline
+ zend_jit_check_exception_undef_result(Dst, opline);
+ if (identical_label != (uint32_t)-1) {
+ | jmp =>identical_label
+ } else {
+ | jmp >9
+ }
+ |8:
+ } else if (identical_label != (uint32_t)-1) {
+ | je =>identical_label
+ } else {
+ | je >9
+ }
+ } else {
+ if (opline->opcode == ZEND_IS_IDENTICAL) {
+ | sete al
+ } else {
+ | setne al
+ }
+ | movzx eax, al
+ | lea eax, [eax + 2]
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+ | SAVE_VALID_OPLINE opline
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 1, op_array, opline
+ zend_jit_check_exception_undef_result(Dst, opline);
+ }
+ if (smart_branch_opcode && not_identical_label != (uint32_t)-1) {
+ | jmp =>not_identical_label
+ }
+ } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
+ zval *val = Z_ZV(op2_addr);
+
+ | cmp byte [FCARG1a + offsetof(zval, u1.v.type)], Z_TYPE_P(val)
+ if (smart_branch_opcode) {
+ if (opline->op1_type == IS_VAR && (op1_info & MAY_BE_REF)) {
+ | jne >8
+ | SAVE_VALID_OPLINE opline
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ zend_jit_check_exception_undef_result(Dst, opline);
+ if (identical_label != (uint32_t)-1) {
+ | jmp =>identical_label
+ } else {
+ | jmp >9
+ }
+ |8:
+ } else if (identical_label != (uint32_t)-1) {
+ | je =>identical_label
+ } else {
+ | je >9
+ }
+ } else {
+ if (opline->opcode == ZEND_IS_IDENTICAL) {
+ | sete al
+ } else {
+ | setne al
+ }
+ | movzx eax, al
+ | lea eax, [eax + 2]
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
+ | SAVE_VALID_OPLINE opline
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ zend_jit_check_exception_undef_result(Dst, opline);
+ }
+ if (smart_branch_opcode && not_identical_label != (uint32_t)-1) {
+ | jmp =>not_identical_label
+ }
+ } else if ((op1_info & MAY_BE_ANY) == MAY_BE_LONG &&
+ (op2_info & MAY_BE_ANY) == MAY_BE_LONG) {
+ if (!zend_jit_cmp_long_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ } else if ((op1_info & MAY_BE_ANY) == MAY_BE_DOUBLE &&
+ (op2_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+ if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ } else {
+ if (opline->op1_type == IS_CONST) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ if (opline->op2_type == IS_CONST) {
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ }
+ | EXT_CALL zend_is_identical, r0
+ if (((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) ||
+ ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) {
+ | mov aword T1, r0 // save
+ | SAVE_VALID_OPLINE opline
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 1, op_array, opline
+ zend_jit_check_exception_undef_result(Dst, opline);
+ | mov r0, aword T1 // restore
+ }
+ if (smart_branch_opcode) {
+ | test al, al
+ if (not_identical_label != (uint32_t)-1) {
+ | jz =>not_identical_label
+ if (identical_label != (uint32_t)-1) {
+ | jmp =>identical_label
+ }
+ } else if (identical_label != (uint32_t)-1) {
+ | jnz =>identical_label
+ }
+ } else {
+ | movzx eax, al
+ if (opline->opcode == ZEND_IS_IDENTICAL) {
+ | lea eax, [eax + 2]
+ } else {
+ | neg eax
+ | lea eax, [eax + 3]
+ }
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ }
+
+ |9:
+ if (may_throw) {
+ zend_jit_check_exception(Dst);
+ }
+
+ return 1;
+}
+
+static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw)
+{
+ uint32_t true_label = -1;
+ uint32_t false_label = -1;
+ zend_bool set_bool = 0;
+ zend_bool set_bool_not = 0;
+ zend_bool jmp_done = 0;
+
+ if (opline->opcode == ZEND_JMPZ) {
+ false_label = target_label;
+ } else if (opline->opcode == ZEND_JMPNZ) {
+ true_label = target_label;
+ } else if (opline->opcode == ZEND_JMPZNZ) {
+ true_label = target_label2;
+ false_label = target_label;
+ } else if (opline->opcode == ZEND_BOOL) {
+ set_bool = 1;
+ } else if (opline->opcode == ZEND_BOOL_NOT) {
+ set_bool = 1;
+ set_bool_not = 1;
+ } else if (opline->opcode == ZEND_JMPZ_EX) {
+ set_bool = 1;
+ false_label = target_label;
+ } else if (opline->opcode == ZEND_JMPNZ_EX) {
+ set_bool = 1;
+ true_label = target_label;
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+ if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
+ if (zend_is_true(Z_ZV(op1_addr))) {
+ /* Always TRUE */
+ if (set_bool) {
+ if (set_bool_not) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ }
+ }
+ if (true_label != (uint32_t)-1) {
+ | jmp =>true_label;
+ }
+ } else {
+ /* Always FALSE */
+ if (set_bool) {
+ if (set_bool_not) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ }
+ }
+ if (false_label != (uint32_t)-1) {
+ | jmp =>false_label;
+ }
+ }
+ return 1;
+ }
+
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | ZVAL_DEREF FCARG1a, op1_info
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ }
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
+ if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
+ /* Always TRUE */
+ if (set_bool) {
+ if (set_bool_not) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ }
+ }
+ if (true_label != (uint32_t)-1) {
+ | jmp =>true_label;
+ }
+ } else {
+ if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
+ /* Always FALSE */
+ if (set_bool) {
+ if (set_bool_not) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ }
+ }
+ } else {
+ | CMP_ZVAL_TYPE op1_addr, IS_TRUE
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
+ if ((op1_info & MAY_BE_LONG) &&
+ !(op1_info & MAY_BE_UNDEF) &&
+ !set_bool) {
+ if (false_label != (uint32_t)-1) {
+ | jl =>false_label
+ } else {
+ | jl >9
+ }
+ jmp_done = 1;
+ } else {
+ | jg >2
+ }
+ }
+ if (!(op1_info & MAY_BE_TRUE)) {
+ /* It's FALSE */
+ if (set_bool) {
+ if (set_bool_not) {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ }
+ }
+ } else {
+ if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
+ if (set_bool) {
+ | jne >1
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ if (true_label != (uint32_t)-1) {
+ | jmp =>true_label
+ } else {
+ | jmp >9
+ }
+ |1:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ } else {
+ if (true_label != (uint32_t)-1) {
+ | je =>true_label
+ } else if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) {
+ | jne =>false_label
+ jmp_done = 1;
+ } else {
+ | je >9
+ }
+ }
+ } else if (set_bool) {
+ | sete al
+ | movzx eax, al
+ if (set_bool_not) {
+ | neg eax
+ | add eax, 3
+ } else {
+ | add eax, 2
+ }
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ }
+ }
+
+ /* It's FALSE, but may be UNDEF */
+ if (op1_info & MAY_BE_UNDEF) {
+ if (op1_info & MAY_BE_ANY) {
+ | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ }
+ | mov FCARG1d, opline->op1.var
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+
+ if (may_throw) {
+ if (!zend_jit_check_exception_undef_result(Dst, opline)) {
+ return 0;
+ }
+ }
+
+ if (false_label != (uint32_t)-1) {
+ | jmp =>false_label
+ }
+ if (op1_info & MAY_BE_ANY) {
+ if (false_label == (uint32_t)-1) {
+ | jmp >9
+ }
+ |.code
+ }
+ }
+
+ if (!jmp_done) {
+ if (false_label != (uint32_t)-1) {
+ | jmp =>false_label
+ } else if (op1_info & MAY_BE_LONG) {
+ | jmp >9
+ }
+ }
+ }
+ }
+
+ if (op1_info & MAY_BE_LONG) {
+ |2:
+ if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2
+ }
+ if (Z_MODE(op1_addr) == IS_REG) {
+ | test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr))
+ } else {
+ | LONG_OP_WITH_CONST, cmp, op1_addr, Z_L(0)
+ }
+ if (set_bool) {
+ | setne al
+ | movzx eax, al
+ if (set_bool_not) {
+ | neg eax
+ | add eax, 3
+ } else {
+ | lea eax, [eax + 2]
+ }
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
+ if (true_label != (uint32_t)-1) {
+ | jne =>true_label
+ if (false_label != (uint32_t)-1) {
+ | jmp =>false_label
+ }
+ } else {
+ | je =>false_label
+ }
+ }
+ }
+
+ if ((op1_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
+ if (zend_jit_x86_flags & ZEND_JIT_CPU_AVX) {
+ | vxorps xmm0, xmm0, xmm0
+ } else {
+ | xorps xmm0, xmm0
+ }
+ | SSE_AVX_OP ucomisd, vucomisd, ZREG_XMM0, op1_addr
+
+ if (set_bool) {
+ if (false_label != (uint32_t)-1) { // JMPZ_EX
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ | jp >1
+ | je => false_label
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ |1:
+ } else if (true_label != (uint32_t)-1) { // JMPNZ_EX
+ | jp >1
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ | jne => true_label
+ |1:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ } else if (set_bool_not) { // BOOL_NOT
+ | jp >1
+ | mov eax, IS_TRUE
+ | je >2
+ |1:
+ | mov eax, IS_FALSE
+ |2:
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ } else { // BOOL
+ | jp >1
+ | mov eax, IS_TRUE
+ | jne >2
+ |1:
+ | mov eax, IS_FALSE
+ |2:
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ }
+ } else {
+ ZEND_ASSERT(true_label != (uint32_t)-1 || false_label != (uint32_t)-1);
+ if (false_label != (uint32_t)-1) {
+ | jp =>false_label
+ } else {
+ | jp >1
+ }
+ if (true_label != (uint32_t)-1) {
+ | jne =>true_label
+ if (false_label != (uint32_t)-1) {
+ | jmp =>false_label
+ }
+ } else {
+ | je =>false_label
+ }
+ |1:
+ }
+ } else if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
+ |.cold_code
+ |2:
+ }
+ if (Z_REG(op1_addr) != ZREG_FCARG1a) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_is_true, r0
+
+ if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
+
+ | IF_NOT_ZVAL_REFCOUNTED op1_addr, >3
+ | GET_ZVAL_PTR FCARG1a, op1_addr
+ | GC_DELREF FCARG1a
+ | jnz >3
+ | mov aword T1, r0 // save
+ | ZVAL_DTOR_FUNC op1_info, opline
+ | mov r0, aword T1 // restore
+ |3:
+ }
+ if (may_throw) {
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r1
+ | jne ->exception_handler_undef
+ }
+
+ if (set_bool) {
+ if (set_bool_not) {
+ | neg eax
+ | add eax, 3
+ } else {
+ | add eax, 2
+ }
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) {
+ | CMP_ZVAL_TYPE res_addr, IS_FALSE
+ if (true_label != (uint32_t)-1) {
+ | jne =>true_label
+ if (false_label != (uint32_t)-1) {
+ | jmp =>false_label
+ } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
+ | jmp >9
+ }
+ } else {
+ | je =>false_label
+ }
+ }
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
+ | jmp >9
+ |.code
+ }
+ } else {
+ | test r0, r0
+ if (true_label != (uint32_t)-1) {
+ | jne =>true_label
+ if (false_label != (uint32_t)-1) {
+ | jmp =>false_label
+ } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
+ | jmp >9
+ }
+ } else {
+ | je =>false_label
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
+ | jmp >9
+ }
+ }
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) {
+ |.code
+ }
+ }
+ }
+
+ |9:
+
+ return 1;
+}
+
+static int zend_jit_qm_assign(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr, uint32_t res_info, zend_jit_addr res_addr)
+{
+ if (op1_addr != op1_def_addr) {
+ if (!zend_jit_update_regs(Dst, op1_addr, op1_def_addr, op1_info)) {
+ return 0;
+ }
+ }
+
+ if (!zend_jit_simple_assign(Dst, opline, op_array, res_addr, -1, -1, opline->op1_type, opline->op1, op1_addr, op1_info, 0, 0)) {
+ return 0;
+ }
+ if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
+ return 0;
+ }
+ return 1;
+}
+
+static int zend_jit_assign(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_use_addr, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr op2_def_addr, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
+{
+ ZEND_ASSERT(opline->op1_type == IS_CV);
+
+ if (op2_addr != op2_def_addr) {
+ if (!zend_jit_update_regs(Dst, op2_addr, op2_def_addr, op2_info)) {
+ return 0;
+ }
+ }
+
+ if (!zend_jit_assign_to_variable(Dst, opline, op_array, op1_addr, op1_info, op1_def_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr)) {
+ return 0;
+ }
+ if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
+ return 0;
+ }
+ if (opline->result_type != IS_UNUSED) {
+ if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) {
+ return 0;
+ }
+ }
+
+ if (may_throw) {
+ zend_jit_check_exception(Dst);
+ }
+
+ return 1;
+}
+
+static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func)
+{
+ uint32_t used_stack;
+
+ if (func) {
+ used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
+ } else {
+ used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value) * sizeof(zval);
+
+ | // if (EXPECTED(ZEND_USER_CODE(func->type))) {
+ | test byte [r0 + offsetof(zend_function, type)], 1
+ | mov FCARG1a, used_stack
+ | jnz >1
+ | // used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
+ | mov edx, opline->extended_value
+ | cmp edx, dword [r0 + offsetof(zend_function, op_array.num_args)]
+ | cmova edx, dword [r0 + offsetof(zend_function, op_array.num_args)]
+ | sub edx, dword [r0 + offsetof(zend_function, op_array.last_var)]
+ | sub edx, dword [r0 + offsetof(zend_function, op_array.T)]
+ | shl edx, 5
+ |.if X64
+ | movsxd r2, edx
+ |.endif
+ | sub FCARG1a, r2
+ |1:
+ }
+
+ zend_jit_start_reuse_ip();
+
+ | // if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
+ | MEM_OP2_2_ZTS mov, RX, aword, executor_globals, vm_stack_top, RX
+ | // Check Stack Overflow
+ | MEM_OP2_2_ZTS mov, r2, aword, executor_globals, vm_stack_end, r2
+ | sub r2, RX
+ if (func) {
+ | cmp r2, used_stack
+ } else {
+ | cmp r2, FCARG1a
+ }
+ | jb >1
+ | // EG(vm_stack_top) = (zval*)((char*)call + used_stack);
+ |.cold_code
+ |1:
+ | SAVE_VALID_OPLINE opline
+ if (func) {
+ | mov FCARG1d, used_stack
+ }
+#ifdef _WIN32
+ if (0) {
+#else
+ if (func && func->type == ZEND_INTERNAL_FUNCTION) {
+#endif
+ | EXT_CALL zend_jit_int_extend_stack_helper, r0
+ } else {
+ | mov FCARG2a, r0
+ | EXT_CALL zend_jit_extend_stack_helper, r0
+ }
+ | mov RX, r0
+ | jmp >1
+ |.code
+
+ if (func) {
+ | MEM_OP2_1_ZTS add, aword, executor_globals, vm_stack_top, used_stack, r2
+ } else {
+ | MEM_OP2_1_ZTS add, aword, executor_globals, vm_stack_top, FCARG1a, r2
+ }
+ | // zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
+ | // ZEND_SET_CALL_INFO(call, 0, call_info);
+ | mov dword EX:RX->This.u1.type_info, (IS_UNDEF | ZEND_CALL_NESTED_FUNCTION)
+ | // call->func = func;
+#ifdef _WIN32
+ if (0) {
+#else
+ if (func && func->type == ZEND_INTERNAL_FUNCTION) {
+#endif
+ |1:
+ | ADDR_OP2_2 mov, aword EX:RX->func, func, r1
+ } else {
+ | mov aword EX:RX->func, r0
+ |1:
+ }
+ | // Z_CE(call->This) = called_scope;
+ | mov aword EX:RX->This.value.ptr, 0
+ | // ZEND_CALL_NUM_ARGS(call) = num_args;
+ | mov dword EX:RX->This.u2.num_args, opline->extended_value
+ return 1;
+}
+
+static int zend_jit_needs_call_chain(zend_call_info *call_info, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline)
+{
+ int skip;
+
+ if (!call_info) {
+ const zend_op *end = op_array->opcodes + op_array->last;
+
+ opline++;
+ skip = 1;
+ while (opline != end) {
+ if (!skip) {
+ if (zend_may_throw(opline, op_array, ssa)) {
+ return 1;
+ }
+ }
+ switch (opline->opcode) {
+ case ZEND_SEND_VAL:
+ case ZEND_SEND_VAR:
+ case ZEND_SEND_VAL_EX:
+ case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_FUNC_ARG:
+ case ZEND_SEND_REF:
+ case ZEND_SEND_VAR_NO_REF:
+ case ZEND_SEND_VAR_NO_REF_EX:
+ skip = 0;
+ break;
+ case ZEND_SEND_ARRAY:
+ case ZEND_SEND_USER:
+ case ZEND_SEND_UNPACK:
+ case ZEND_INIT_FCALL:
+ case ZEND_INIT_METHOD_CALL:
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ case ZEND_INIT_FCALL_BY_NAME:
+ case ZEND_INIT_NS_FCALL_BY_NAME:
+ case ZEND_INIT_DYNAMIC_CALL:
+ case ZEND_NEW:
+ case ZEND_INIT_USER_CALL:
+ case ZEND_FAST_CALL:
+ case ZEND_JMP:
+ case ZEND_JMPZNZ:
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ case ZEND_FE_RESET_R:
+ case ZEND_FE_RESET_RW:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_ASSERT_CHECK:
+ case ZEND_CATCH:
+ case ZEND_DECLARE_ANON_CLASS:
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+ return 1;
+ case ZEND_DO_ICALL:
+ case ZEND_DO_UCALL:
+ case ZEND_DO_FCALL_BY_NAME:
+ case ZEND_DO_FCALL:
+ end = opline;
+ if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
+ /* INIT_FCALL and DO_FCALL in different BasicBlocks */
+ return 1;
+ }
+ return 0;
+ }
+ opline++;
+ }
+
+ return 1;
+ } else {
+ const zend_op *end = call_info->caller_call_opline;
+
+ if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
+ /* INIT_FCALL and DO_FCALL in different BasicBlocks */
+ return 1;
+ }
+
+ opline++;
+ skip = 1;
+ while (opline != end) {
+ if (skip) {
+ switch (opline->opcode) {
+ case ZEND_SEND_VAL:
+ case ZEND_SEND_VAR:
+ case ZEND_SEND_VAL_EX:
+ case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_FUNC_ARG:
+ case ZEND_SEND_REF:
+ case ZEND_SEND_VAR_NO_REF:
+ case ZEND_SEND_VAR_NO_REF_EX:
+ skip = 0;
+ break;
+ case ZEND_SEND_ARRAY:
+ case ZEND_SEND_USER:
+ case ZEND_SEND_UNPACK:
+ return 1;
+ }
+ } else {
+ if (zend_may_throw(opline, op_array, ssa)) {
+ return 1;
+ }
+ }
+ opline++;
+ }
+
+ return 0;
+ }
+}
+
+static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, int call_level)
+{
+ zend_func_info *info = ZEND_FUNC_INFO(op_array);
+ zend_call_info *call_info = NULL;
+ zend_function *func = NULL;
+
+ if (delayed_call_chain) {
+ if (!zend_jit_save_call_chain(Dst, delayed_call_level)) {
+ return 0;
+ }
+ }
+
+ if (info) {
+ call_info = info->callee_info;
+ while (call_info && call_info->caller_init_opline != opline) {
+ call_info = call_info->next_callee;
+ }
+ if (call_info && call_info->callee_func) {
+ func = call_info->callee_func;
+ }
+ }
+
+#ifdef _WIN32
+ if (0) {
+#else
+ if (func && func->type == ZEND_INTERNAL_FUNCTION) {
+#endif
+ /* load constant address later */
+ } else if (func && op_array == &func->op_array) {
+ /* recursive call */
+ | mov r0, EX->func
+ } else {
+ | // if (CACHED_PTR(opline->result.num))
+ | mov r0, EX->run_time_cache
+ | mov r0, aword [r0 + opline->result.num]
+ | test r0, r0
+ | jz >1
+ |.cold_code
+ |1:
+ if (func && func->type == ZEND_USER_FUNCTION && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
+ | LOAD_ADDR FCARG1a, func
+ | EXT_CALL zend_jit_init_func_run_time_cache_helper, r0
+ | mov r1, EX->run_time_cache
+ | mov aword [r1 + opline->result.num], r0
+ | jmp >3
+ } else {
+ zval *zv = RT_CONSTANT(opline, opline->op2);
+
+ if (opline->opcode == ZEND_INIT_FCALL) {
+ | LOAD_ADDR FCARG1a, Z_STR_P(zv);
+ } else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
+ | LOAD_ADDR FCARG1a, Z_STR_P(zv + 1);
+ } else {
+ ZEND_ASSERT(0);
+ }
+ | EXT_CALL zend_jit_find_func_helper, r0
+ | // CACHE_PTR(opline->result.num, fbc);
+ | mov r1, EX->run_time_cache
+ | mov aword [r1 + opline->result.num], r0
+ | test r0, r0
+ | jnz >3
+ | // SAVE_OPLINE();
+ | SAVE_VALID_OPLINE opline
+ | jmp ->undefined_function
+ }
+ |.code
+ |3:
+ }
+
+ if (!zend_jit_push_call_frame(Dst, opline, op_array, func)) {
+ return 0;
+ }
+
+ if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, opline)) {
+ if (!zend_jit_save_call_chain(Dst, call_level)) {
+ return 0;
+ }
+ } else {
+ delayed_call_chain = 1;
+ delayed_call_level = call_level;
+ }
+
+ return 1;
+}
+
+static uint32_t skip_valid_arguments(const zend_op_array *op_array, zend_ssa *ssa, zend_call_info *call_info)
+{
+ uint32_t num_args = 0;
+ zend_function *func = call_info->callee_func;
+
+ while (num_args < call_info->num_args) {
+ zend_arg_info *arg_info = func->op_array.arg_info + num_args;
+
+ if (ZEND_TYPE_IS_SET(arg_info->type)) {
+ if (ZEND_TYPE_IS_ONLY_MASK(arg_info->type)) {
+ uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type);
+ uint32_t info = _ssa_op1_info(op_array, ssa, call_info->arg_info[num_args].opline);
+ if ((info & (MAY_BE_ANY|MAY_BE_UNDEF)) & ~type_mask) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ num_args++;
+ }
+ return num_args;
+}
+
+static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, unsigned int next_block)
+{
+ zend_func_info *info = ZEND_FUNC_INFO(op_array);
+ zend_call_info *call_info = NULL;
+ zend_function *func = NULL;
+ uint32_t i;
+ zend_jit_addr res_addr;
+
+ if (RETURN_VALUE_USED(opline)) {
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+ } else {
+#ifdef _WIN64
+ /* Reuse reserved arguments stack */
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R4, 0x20);
+#else
+ /* CPU stack allocated temporary zval */
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R4, 8);
+#endif
+ }
+
+ if (info) {
+ call_info = info->callee_info;
+ while (call_info && call_info->caller_call_opline != opline) {
+ call_info = call_info->next_callee;
+ }
+ if (call_info && call_info->callee_func) {
+ func = call_info->callee_func;
+ }
+ }
+ if (!func) {
+ /* resolve function ar run time */
+ } else if (func->type == ZEND_USER_FUNCTION) {
+ ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
+ if (call_info->num_args > func->op_array.num_args ||
+ (opline-1)->opcode == ZEND_SEND_UNPACK ||
+ (opline-1)->opcode == ZEND_SEND_ARRAY) {
+ goto fallback;
+ }
+ } else if (func->type == ZEND_INTERNAL_FUNCTION) {
+ ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
+#if ZEND_DEBUG
+ if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ goto fallback;
+ }
+#endif
+ if ((opline-1)->opcode == ZEND_SEND_UNPACK || (opline-1)->opcode == ZEND_SEND_ARRAY) {
+ goto fallback;
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+ if (!reuse_ip) {
+ zend_jit_start_reuse_ip();
+ | // call = EX(call);
+ | mov RX, EX->call
+ }
+ zend_jit_stop_reuse_ip();
+
+ | // fbc = call->func;
+ | // mov r2, EX:RX->func ???
+ | // SAVE_OPLINE();
+ | SAVE_VALID_OPLINE opline
+
+ if (!delayed_call_chain) {
+ if (call_level == 1) {
+ | mov aword EX->call, 0
+ } else {
+ | //EX(call) = call->prev_execute_data;
+ | mov r0, EX:RX->prev_execute_data
+ | mov EX->call, r0
+ }
+ }
+ delayed_call_chain = 0;
+
+ | //call->prev_execute_data = execute_data;
+ | mov EX:RX->prev_execute_data, EX
+
+ if (!func) {
+ | mov r0, EX:RX->func
+ }
+
+ if (opline->opcode == ZEND_DO_FCALL) {
+ if (!func) {
+ | test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED
+ | jnz >1
+ |.cold_code
+ |1:
+ if (!GCC_GLOBAL_REGS) {
+ | mov FCARG1a, RX
+ }
+ | EXT_CALL zend_jit_deprecated_helper, r0
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | jne ->exception_handler
+ | mov r0, EX:RX->func // reload
+ | jmp >1
+ |.code
+ |1:
+ } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
+ if (!GCC_GLOBAL_REGS) {
+ | mov FCARG1a, RX
+ }
+ | EXT_CALL zend_jit_deprecated_helper, r0
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | jne ->exception_handler
+ | mov r0, EX:RX->func // reload
+ }
+ }
+
+ if (!func
+ && opline->opcode != ZEND_DO_UCALL
+ && opline->opcode != ZEND_DO_ICALL) {
+ | cmp byte [r0 + offsetof(zend_function, type)], ZEND_USER_FUNCTION
+ | jne >8
+ }
+
+ if ((!func || func->type == ZEND_USER_FUNCTION)
+ && opline->opcode != ZEND_DO_ICALL) {
+ | // EX(call) = NULL;
+ | mov aword EX:RX->call, 0
+
+ if (RETURN_VALUE_USED(opline)) {
+ | // EX(return_value) = EX_VAR(opline->result.var);
+ | LOAD_ZVAL_ADDR r2, res_addr
+ | mov aword EX:RX->return_value, r2
+ } else {
+ | // EX(return_value) = 0;
+ | mov aword EX:RX->return_value, 0
+ }
+
+ if (func) {
+ for (i = call_info->num_args; i < func->op_array.last_var; i++) {
+ uint32_t n = (uint32_t)(uintptr_t)ZEND_CALL_VAR_NUM(NULL, i);
+ | SET_Z_TYPE_INFO RX + n, IS_UNDEF
+ }
+ }
+
+ //EX_LOAD_RUN_TIME_CACHE(op_array);
+ if (!func || func->op_array.cache_size) {
+ if (func && op_array == &func->op_array) {
+ /* recursive call */
+ if (func->op_array.cache_size > sizeof(void*)) {
+ | mov r2, EX->run_time_cache
+ | mov EX:RX->run_time_cache, r2
+ }
+ } else {
+ if (func) {
+ | mov r0, EX:RX->func
+ }
+ | mov r2, aword [r0 + offsetof(zend_op_array, run_time_cache__ptr)]
+#if ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR
+ | mov r2, aword [r2]
+#elif ZEND_MAP_PTR_KIND == ZEND_MAP_PTR_KIND_PTR_OR_OFFSET
+ | test r2, 1
+ | jz >1
+ | MEM_OP2_2_ZTS add, r2, aword, compiler_globals, map_ptr_base, r1
+ |1:
+ | mov r2, aword [r2]
+#else
+# error "Unknown ZEND_MAP_PTR_KIND"
+#endif
+ | mov EX:RX->run_time_cache, r2
+ }
+ }
+
+ | // EG(current_execute_data) = execute_data;
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, RX, r1
+ | mov FP, RX
+
+ | // opline = op_array->opcodes;
+ if (func) {
+ uint32_t num_args;
+
+ if (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+ num_args = skip_valid_arguments(op_array, ssa, call_info);
+ } else {
+ num_args = call_info->num_args;
+ }
+ if (func && zend_accel_in_shm(func->op_array.opcodes)) {
+ | LOAD_IP_ADDR (func->op_array.opcodes + num_args)
+ } else {
+ if (func) {
+ | mov r0, EX->func
+ }
+ if (GCC_GLOBAL_REGS) {
+ | mov IP, aword [r0 + offsetof(zend_op_array, opcodes)]
+ if (num_args) {
+ | add IP, (num_args * sizeof(zend_op))
+ }
+ } else {
+ | mov FCARG1a, aword [r0 + offsetof(zend_op_array, opcodes)]
+ if (num_args) {
+ | add FCARG1a, (num_args * sizeof(zend_op))
+ }
+ | mov aword EX->opline, FCARG1a
+ }
+ }
+
+ if (op_array == &func->op_array) {
+ /* recursive call */
+#ifdef CONTEXT_THREADED_JIT
+ | call >1
+ |.cold_code
+ |1:
+ | pop r0
+ | jmp =>num_args
+ |.code
+#else
+ | jmp =>num_args
+#endif
+ return 1;
+ }
+ } else {
+ | // opline = op_array->opcodes
+ if (GCC_GLOBAL_REGS) {
+ | mov IP, aword [r0 + offsetof(zend_op_array, opcodes)]
+ } else {
+ | mov FCARG1a, aword [r0 + offsetof(zend_op_array, opcodes)]
+ | mov aword EX->opline, FCARG1a
+ }
+ | // first_extra_arg = op_array->num_args;
+ | mov edx, dword [r0 + offsetof(zend_op_array, num_args)]
+ | // num_args = EX_NUM_ARGS();
+ | mov ecx, dword [FP + offsetof(zend_execute_data, This.u2.num_args)]
+ | // if (UNEXPECTED(num_args > first_extra_arg))
+ | cmp edx, ecx
+ | jl >1
+ |.cold_code
+ |1:
+ if (!GCC_GLOBAL_REGS) {
+ | mov FCARG1a, FP
+ }
+ | EXT_CALL zend_jit_copy_extra_args_helper, r0
+ | mov r0, EX->func // reload
+ | mov ecx, dword [FP + offsetof(zend_execute_data, This.u2.num_args)] // reload
+ | jmp >1
+ |.code
+ | // if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
+ | test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_HAS_TYPE_HINTS
+ | jnz >1
+ | // opline += num_args;
+ |.if X64
+ | movsxd r2, ecx
+ | imul r2, r2, sizeof(zend_op)
+ |.else
+ | imul r2, ecx, sizeof(zend_op)
+ |.endif
+ | ADD_IP r2
+ |1:
+ | // if (EXPECTED((int)num_args < op_array->last_var)) {
+ | mov edx, dword [r0 + offsetof(zend_op_array, last_var)]
+ | sub edx, ecx
+ | jle >3 //???
+ | // zval *var = EX_VAR_NUM(num_args);
+ |.if X64
+ | movsxd r1, ecx
+ |.endif
+ | shl r1, 4
+ | lea r1, [FP + r1 + (ZEND_CALL_FRAME_SLOT * sizeof(zval))]
+ |2:
+ | SET_Z_TYPE_INFO r1, IS_UNDEF
+ | sub edx, 1
+ | lea r1, [r1 + 16]
+ | jne <2
+ |3:
+ }
+
+#ifdef CONTEXT_THREADED_JIT
+ | call ->context_threaded_call
+ if (!func && (opline->opcode != ZEND_DO_UCALL)) {
+ | jmp >9
+ }
+#else
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ | add r4, HYBRID_SPAD
+ | JMP_IP
+ } else if (GCC_GLOBAL_REGS) {
+ | add r4, SPAD // stack alignment
+ | JMP_IP
+ } else {
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ | mov r0, 1 // ZEND_VM_ENTER
+ | ret
+ }
+#endif
+ }
+
+ if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
+ && (opline->opcode != ZEND_DO_UCALL)) {
+ if (!func && (opline->opcode != ZEND_DO_ICALL)) {
+ |8:
+ }
+ if (opline->opcode == ZEND_DO_FCALL_BY_NAME) {
+ if (!func) {
+ | test dword [r0 + offsetof(zend_op_array, fn_flags)], ZEND_ACC_DEPRECATED
+ | jnz >1
+ |.cold_code
+ |1:
+ if (!GCC_GLOBAL_REGS) {
+ | mov FCARG1a, RX
+ }
+ | EXT_CALL zend_jit_deprecated_helper, r0
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | jne ->exception_handler
+ | mov r0, EX:RX->func // reload
+ | jmp >1
+ |.code
+ |1:
+ } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
+ if (!GCC_GLOBAL_REGS) {
+ | mov FCARG1a, RX
+ }
+ | EXT_CALL zend_jit_deprecated_helper, r0
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | jne ->exception_handler
+ | mov r0, EX:RX->func // reload
+ }
+ }
+
+ if (!RETURN_VALUE_USED(opline)) {
+ |.if not(X64WIN)
+ | sub r4, 16 /* alloca() */
+ |.endif
+ }
+
+ | // ZVAL_NULL(EX_VAR(opline->result.var));
+ | LOAD_ZVAL_ADDR FCARG2a, res_addr
+ | SET_Z_TYPE_INFO FCARG2a, IS_NULL
+
+ | // EG(current_execute_data) = execute_data;
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, RX, r1
+
+ zend_jit_reset_opline(Dst, NULL);
+
+ | // fbc->internal_function.handler(call, ret);
+ | mov FCARG1a, RX
+ if (func) {
+ | EXT_CALL func->internal_function.handler, r0
+ } else {
+ | call aword [r0 + offsetof(zend_internal_function, handler)]
+ }
+
+ | // EG(current_execute_data) = execute_data;
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, FP, r0
+
+ | // zend_vm_stack_free_args(call);
+ if (func) {
+ for (i = 0; i < call_info->num_args; i++ ) {
+ uint32_t offset = (uint32_t)(uintptr_t)ZEND_CALL_VAR_NUM(NULL, i);
+ | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset), MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, 1, 0, opline
+ }
+ } else {
+ | mov FCARG1a, RX
+ | EXT_CALL zend_jit_vm_stack_free_args_helper, r0
+ }
+
+ |8:
+ if (opline->opcode == ZEND_DO_FCALL) {
+ // TODO: optimize ???
+ | // if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
+ | test byte [RX + offsetof(zend_execute_data, This.u1.type_info) + 2], (ZEND_CALL_RELEASE_THIS >> 16)
+ | jnz >1
+ |.cold_code
+ |1:
+ | GET_Z_PTR r0, RX + offsetof(zend_execute_data, This)
+ | // OBJ_RELEASE(object);
+ | OBJ_RELEASE r0, ecx, >2
+ | jmp >2
+ |.code
+ |2:
+ }
+
+ | // zend_vm_stack_free_call_frame(call);
+ | test byte [RX + offsetof(zend_execute_data, This.u1.type_info) + 2], (ZEND_CALL_ALLOCATED >> 16)
+ | jnz >1
+ |.cold_code
+ |1:
+ | mov FCARG1a, RX
+ | EXT_CALL zend_jit_free_call_frame, r0
+ | jmp >1
+ |.code
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, vm_stack_top, RX, r0
+ |1:
+
+ if (!RETURN_VALUE_USED(opline)) {
+ uint32_t func_info = call_info ?
+ zend_get_func_info(call_info, ssa) :
+ (MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
+
+ if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
+ | ZVAL_PTR_DTOR res_addr, func_info, 1, 1, 0, opline
+ }
+ |.if not(X64WIN)
+ | add r4, 16 /* revert alloca() */
+ |.endif
+ }
+
+ | // if (UNEXPECTED(EG(exception) != NULL)) {
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | jne >1
+ |.cold_code
+ |1:
+ | LOAD_IP_ADDR opline
+ | jmp ->icall_throw_handler
+ |.code
+
+ // TODO: Can we avoid checking for interrupts after each call ???
+ if (!zend_jit_check_timeout(Dst, opline + 1)) {
+ return 0;
+ }
+ if (opline->opcode != ZEND_DO_ICALL) {
+ | LOAD_IP_ADDR (opline + 1)
+ }
+ }
+
+ if (!func) {
+ |9:
+ }
+
+ return 1;
+
+fallback:
+ /* fallback to subroutine threading */
+ if (opline->opcode == ZEND_DO_FCALL ||
+ opline->opcode == ZEND_DO_UCALL ||
+ opline->opcode == ZEND_DO_FCALL_BY_NAME ){
+ return zend_jit_call(Dst, opline, next_block);
+ } else {
+ return zend_jit_handler(Dst, opline, zend_may_throw(opline, op_array, ssa));
+ }
+}
+
+static int zend_jit_send_val(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr)
+{
+ uint32_t arg_num = opline->op2.num;
+ zend_jit_addr arg_addr;
+
+ ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
+
+ if (!reuse_ip) {
+ zend_jit_start_reuse_ip();
+ | // call = EX(call);
+ | mov RX, EX->call
+ }
+
+ if (opline->opcode == ZEND_SEND_VAL_EX) {
+ uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
+
+ | mov r0, EX:RX->func
+ if (arg_num <= MAX_ARG_FLAG_NUM) {
+ | test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
+ | jnz >1
+ } else {
+ ZEND_ASSERT(0);
+ }
+ |.cold_code
+ |1:
+ | SAVE_VALID_OPLINE opline
+ | jmp ->throw_cannot_pass_by_ref
+ |.code
+ }
+
+ arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
+
+ if (opline->op1_type == IS_CONST) {
+ zval *zv = RT_CONSTANT(opline, opline->op1);
+
+ | ZVAL_COPY_CONST arg_addr, -1, -1, zv, r0
+ if (Z_REFCOUNTED_P(zv)) {
+ | ADDREF_CONST zv, r0
+ }
+ } else {
+ | ZVAL_COPY_VALUE arg_addr, -1, op1_addr, op1_info, ZREG_R0, ZREG_R2
+ }
+
+ return 1;
+}
+
+static int zend_jit_send_ref(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int cold)
+{
+ zend_jit_addr op1_addr, arg_addr, ref_addr;
+
+ op1_addr = OP1_ADDR();
+ arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
+
+ if (!reuse_ip) {
+ zend_jit_start_reuse_ip();
+ | // call = EX(call);
+ | mov RX, EX->call
+ }
+
+ if (opline->op1_type == IS_VAR) {
+ | LOAD_ZVAL_ADDR r0, op1_addr
+ | // if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
+ | IF_NOT_Z_TYPE r0, IS_INDIRECT, >1
+ | // ret = Z_INDIRECT_P(ret);
+ | GET_Z_PTR r0, r0
+ |1:
+ } else if (opline->op1_type == IS_CV) {
+ if (op1_info & MAY_BE_UNDEF) {
+ if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
+ | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL
+ | jmp >2
+ |1:
+ }
+ op1_info &= ~MAY_BE_UNDEF;
+ op1_info |= MAY_BE_NULL;
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+ if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
+ if (op1_info & MAY_BE_REF) {
+ if (opline->op1_type == IS_VAR) {
+ | IF_NOT_Z_TYPE r0, IS_REFERENCE, >2
+ | GET_Z_PTR r1, r0
+ } else {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >2
+ | GET_ZVAL_PTR r1, op1_addr
+ }
+ | GC_ADDREF r1
+ | SET_ZVAL_PTR arg_addr, r1
+ | SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX
+ | jmp >6
+ }
+ |2:
+ | // ZVAL_NEW_REF(arg, varptr);
+ if (opline->op1_type == IS_VAR) {
+ | mov aword T1, r0 // save
+ }
+ | EMALLOC sizeof(zend_reference), op_array, opline
+ | mov dword [r0], 2
+ | mov dword [r0 + offsetof(zend_reference, gc.u.type_info)], IS_REFERENCE
+ | mov aword [r0 + offsetof(zend_reference, sources.ptr)], 0
+ ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 8);
+ if (opline->op1_type == IS_VAR) {
+ zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R1, 0);
+
+ | mov r1, aword T1 // restore
+ | ZVAL_COPY_VALUE ref_addr, -1, val_addr, op1_info, ZREG_R2, ZREG_R2
+ | SET_ZVAL_PTR val_addr, r0
+ | SET_ZVAL_TYPE_INFO val_addr, IS_REFERENCE_EX
+ } else {
+ | ZVAL_COPY_VALUE ref_addr, -1, op1_addr, op1_info, ZREG_R1, ZREG_R2
+ | SET_ZVAL_PTR op1_addr, r0
+ | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
+ }
+ | SET_ZVAL_PTR arg_addr, r0
+ | SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX
+ }
+
+ |6:
+ | FREE_OP opline->op1_type, opline->op1, op1_info, !cold, op_array, opline
+ |7:
+
+ return 1;
+}
+
+static int zend_jit_send_var(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr)
+{
+ uint32_t arg_num = opline->op2.num;
+ zend_jit_addr arg_addr;
+
+ ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
+ opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
+ arg_num <= MAX_ARG_FLAG_NUM);
+
+ arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
+
+ if (!reuse_ip) {
+ zend_jit_start_reuse_ip();
+ | // call = EX(call);
+ | mov RX, EX->call
+ }
+
+ if (opline->opcode == ZEND_SEND_VAR_EX || opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
+ uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
+
+ | mov r0, EX:RX->func
+ if (arg_num <= MAX_ARG_FLAG_NUM) {
+ | test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
+ | jnz >1
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+ |.cold_code
+ |1:
+
+ if (opline->opcode == ZEND_SEND_VAR_EX) {
+ if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) {
+ return 0;
+ }
+ } else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
+ mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
+
+ | ZVAL_COPY_VALUE arg_addr, -1, op1_addr, op1_info, ZREG_R1, ZREG_R2
+ if (op1_info & MAY_BE_REF) {
+ | cmp cl, IS_REFERENCE
+ | je >7
+ }
+ | test dword [r0 + offsetof(zend_function, quick_arg_flags)], mask
+ | jnz >7
+ | SAVE_VALID_OPLINE opline
+ | LOAD_ZVAL_ADDR FCARG1a, arg_addr
+ | EXT_CALL zend_jit_only_vars_by_reference, r0
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+
+ | jmp >7
+ |.code
+ }
+
+ if (op1_info & MAY_BE_UNDEF) {
+ if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
+ | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ }
+
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1d, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ | SET_ZVAL_TYPE_INFO arg_addr, IS_NULL
+
+ if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
+ | jmp >7
+ |.code
+ }
+ }
+
+ if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
+ | ZVAL_COPY_VALUE arg_addr, -1, op1_addr, op1_info, ZREG_R1, ZREG_R2
+ if (op1_info & MAY_BE_REF) {
+ | cmp cl, IS_REFERENCE
+ | je >7
+ }
+ | SAVE_VALID_OPLINE opline
+ | LOAD_ZVAL_ADDR FCARG1a, arg_addr
+ | EXT_CALL zend_jit_only_vars_by_reference, r0
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ } else if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
+ if (op1_info & MAY_BE_REF) {
+ if (opline->op1_type == IS_CV) {
+ zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | ZVAL_DEREF FCARG1a, op1_info
+ | ZVAL_COPY_VALUE arg_addr, -1, val_addr, op1_info, ZREG_R0, ZREG_R2
+ | TRY_ADDREF op1_info, ah, r2
+ } else {
+ zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 8);
+
+ | IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1
+ |.cold_code
+ |1:
+ | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
+ | GET_ZVAL_PTR FCARG1a, op1_addr
+ | // ZVAL_COPY_VALUE(return_value, &ref->value);
+ | ZVAL_COPY_VALUE arg_addr, -1, ref_addr, op1_info, ZREG_R0, ZREG_R2
+ | GC_DELREF FCARG1a
+ | je >1
+ | IF_NOT_REFCOUNTED ah, >2
+ | GC_ADDREF r2
+ | jmp >2
+ |1:
+ | EFREE_REG_24 op_array, opline
+ | jmp >2
+ |.code
+ | ZVAL_COPY_VALUE arg_addr, -1, op1_addr, op1_info, ZREG_R0, ZREG_R2
+ |2:
+ }
+ } else {
+ if (op1_addr != op1_def_addr) {
+ if (!zend_jit_update_regs(Dst, op1_addr, op1_def_addr, op1_info)) {
+ return 0;
+ }
+ if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
+ op1_addr= op1_def_addr;
+ }
+ }
+ | ZVAL_COPY_VALUE arg_addr, -1, op1_addr, op1_info, ZREG_R0, ZREG_R2
+ if (opline->op1_type == IS_CV) {
+ | TRY_ADDREF op1_info, ah, r2
+ }
+ }
+ }
+ |7:
+
+ return 1;
+}
+
+static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ if (jmp) {
+ | jmp >7
+ }
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ | jmp =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ | jmp =>target_label2
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ if (jmp) {
+ | jmp >7
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, zend_uchar smart_branch_opcode, uint32_t target_label)
+{
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ | jmp =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ if (jmp) {
+ | jmp >7
+ }
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ | jmp =>target_label
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ if (jmp) {
+ | jmp >7
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ uint32_t defined_label = (uint32_t)-1;
+ uint32_t undefined_label = (uint32_t)-1;
+ zval *zv = RT_CONSTANT(opline, opline->op1);
+ zend_jit_addr res_addr;
+
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ undefined_label = target_label;
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ defined_label = target_label;
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ undefined_label = target_label;
+ defined_label = target_label2;
+ } else {
+ ZEND_ASSERT(0);
+ }
+ }
+
+ | // if (CACHED_PTR(opline->extended_value)) {
+ | mov r0, EX->run_time_cache
+ | mov r0, aword [r0 + opline->extended_value]
+ | test r0, r0
+ | jz >1
+ | test r0, 0x1
+ | jnz >4
+ |.cold_code
+ |4:
+ | MEM_OP2_2_ZTS mov, FCARG1a, aword, executor_globals, zend_constants, FCARG1a
+ | shr r0, 1
+ | cmp dword [FCARG1a + offsetof(HashTable, nNumOfElements)], eax
+ if (smart_branch_opcode) {
+ if (undefined_label != (uint32_t)-1) {
+ | jz =>undefined_label
+ } else {
+ | jz >3
+ }
+ } else {
+ | jz >2
+ }
+ |1:
+ | SAVE_VALID_OPLINE opline
+ | LOAD_ADDR FCARG1a, zv
+ | EXT_CALL zend_jit_check_constant, r0
+ | test r0, r0
+ if (smart_branch_opcode) {
+ if (undefined_label != (uint32_t)-1) {
+ | jnz =>undefined_label
+ } else {
+ | jnz >3
+ }
+ if (defined_label != (uint32_t)-1) {
+ | jmp =>defined_label
+ } else {
+ | jmp >3
+ }
+ } else {
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+ | jz >1
+ |2:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ | jmp >3
+ }
+ |.code
+ if (smart_branch_opcode) {
+ if (defined_label != (uint32_t)-1) {
+ | jmp =>defined_label
+ }
+ } else {
+ |1:
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ }
+ |3:
+
+ return 1;
+}
+
+static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ uint32_t mask;
+ zend_uchar type;
+ zend_jit_addr op1_addr = OP1_ADDR();
+
+ // TODO: support for is_resource() ???
+ ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
+
+ if (op1_info & MAY_BE_UNDEF) {
+ if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
+ | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1
+ |.cold_code
+ |1:
+ }
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1d, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ zend_jit_check_exception_undef_result(Dst, opline);
+ if (opline->extended_value & MAY_BE_NULL) {
+ if (!zend_jit_smart_true(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ } else {
+ if (!zend_jit_smart_false(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label)) {
+ return 0;
+ }
+ }
+ if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
+ |.code
+ }
+ }
+
+ if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
+ mask = opline->extended_value;
+ switch (mask) {
+ case MAY_BE_NULL: type = IS_NULL; break;
+ case MAY_BE_FALSE: type = IS_FALSE; break;
+ case MAY_BE_TRUE: type = IS_TRUE; break;
+ case MAY_BE_LONG: type = IS_LONG; break;
+ case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
+ case MAY_BE_STRING: type = IS_STRING; break;
+ case MAY_BE_ARRAY: type = IS_ARRAY; break;
+ case MAY_BE_OBJECT: type = IS_OBJECT; break;
+ default:
+ type = 0;
+ }
+
+ if (!(op1_info & (MAY_BE_ANY - mask))) {
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ if (!zend_jit_smart_true(Dst, opline, 0, smart_branch_opcode, target_label, target_label2)) {
+ return 0;
+ }
+ } else if (!(op1_info & mask)) {
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ if (!zend_jit_smart_false(Dst, opline, 0, smart_branch_opcode, target_label)) {
+ return 0;
+ }
+ } else {
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR r0, op1_addr
+ | ZVAL_DEREF r0, op1_info
+ }
+ if (type == 0) {
+ if (smart_branch_opcode &&
+ (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ | // if (Z_REFCOUNTED_P(cv)) {
+ | IF_ZVAL_REFCOUNTED op1_addr, >1
+ |.cold_code
+ |1:
+ }
+ | // if (!Z_DELREF_P(cv)) {
+ | GET_ZVAL_PTR FCARG1a, op1_addr
+ | GC_DELREF FCARG1a
+ if (RC_MAY_BE_1(op1_info)) {
+ if (RC_MAY_BE_N(op1_info)) {
+ | jnz >3
+ }
+ if (op1_info & MAY_BE_REF) {
+ | mov al, byte [r0 + 8]
+ } else {
+ | mov al, byte [FP + opline->op1.var + 8]
+ }
+ | mov byte T1, al // save
+ | // zval_dtor_func(r);
+ | ZVAL_DTOR_FUNC op1_info, opline
+ | mov cl, byte T1 // restore
+ |jmp >2
+ }
+ if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ if (!RC_MAY_BE_1(op1_info)) {
+ | jmp >3
+ }
+ |.code
+ }
+ |3:
+ if (op1_info & MAY_BE_REF) {
+ | mov cl, byte [r0 + 8]
+ } else {
+ | mov cl, byte [FP + opline->op1.var + 8]
+ }
+ |2:
+ } else {
+ if (op1_info & MAY_BE_REF) {
+ | mov cl, byte [r0 + 8]
+ } else {
+ | mov cl, byte [FP + opline->op1.var + 8]
+ }
+ }
+ | mov eax, 1
+ | shl eax, cl
+ | test eax, mask
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ | je =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ | jne =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ | je =>target_label
+ | jmp =>target_label2
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ | setne al
+ | movzx eax, al
+ | add eax, 2
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ }
+ } else {
+ if (smart_branch_opcode &&
+ (opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ | // if (Z_REFCOUNTED_P(cv)) {
+ | IF_ZVAL_REFCOUNTED op1_addr, >1
+ |.cold_code
+ |1:
+ }
+ | // if (!Z_DELREF_P(cv)) {
+ | GET_ZVAL_PTR FCARG1a, op1_addr
+ | GC_DELREF FCARG1a
+ if (RC_MAY_BE_1(op1_info)) {
+ if (RC_MAY_BE_N(op1_info)) {
+ | jnz >3
+ }
+ if (op1_info & MAY_BE_REF) {
+ | mov al, byte [r0 + 8]
+ } else {
+ | mov al, byte [FP + opline->op1.var + 8]
+ }
+ | mov byte T1, al // save
+ | // zval_dtor_func(r);
+ | ZVAL_DTOR_FUNC op1_info, opline
+ | mov cl, byte T1 // restore
+ |jmp >2
+ }
+ if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ if (!RC_MAY_BE_1(op1_info)) {
+ | jmp >3
+ }
+ |.code
+ }
+ |3:
+ if (op1_info & MAY_BE_REF) {
+ | mov cl, byte [r0 + 8]
+ } else {
+ | mov cl, byte [FP + opline->op1.var + 8]
+ }
+ |2:
+ | cmp cl, type
+ } else {
+ if (op1_info & MAY_BE_REF) {
+ | cmp byte [r0 + 8], type
+ } else {
+ | cmp byte [FP + opline->op1.var + 8], type
+ }
+ }
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ | jne =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ | je =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ | jne =>target_label
+ | jmp =>target_label2
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ | sete al
+ | movzx eax, al
+ | add eax, 2
+ | SET_ZVAL_TYPE_INFO res_addr, eax
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+ }
+ }
+ }
+ }
+
+ |7:
+
+ return 1;
+}
+
+static int zend_jit_free_compiled_variables(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa)
+{
+ uint32_t i, j, info;
+
+ // Use type inference to avoid useless zval_ptr_dtor()
+ for (i = 0 ; i < op_array->last_var; i++) {
+ if (ssa->vars && ssa->var_info) {
+ info = ssa->var_info[i].type;
+ for (j = op_array->last_var; j < ssa->vars_count; j++) {
+ if (ssa->vars[j].var == i) {
+ info |= ssa->var_info[j].type;
+ }
+ }
+ } else {
+ info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_UNDEF;
+ }
+
+#ifdef ZEND_JIT_USE_RC_INFERENCE
+ /* Refcount may be increased by RETURN opcode */
+ if ((info & MAY_BE_RC1) && !(info & MAY_BE_RCN)) {
+ for (j = 0; j < ssa->cfg.blocks_count; j++) {
+ if ((ssa->cfg.blocks[j].flags & ZEND_BB_REACHABLE) &&
+ ssa->cfg.blocks[j].len > 0) {
+ const zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].start + ssa->cfg.blocks[j].len - 1;
+
+ if (opline->opcode == ZEND_RETURN) {
+ if (opline->op1_type == IS_CV &&
+ opline->op1.var == (uint32_t)(uintptr_t)(ZEND_CALL_VAR_NUM(NULL, i))) {
+ info |= MAY_BE_RCN;
+ break;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
+ uint32_t offset = (uint32_t)(uintptr_t)ZEND_CALL_VAR_NUM(NULL, i);
+ | ZVAL_PTR_DTOR ZEND_ADDR_MEM_ZVAL(ZREG_FP, offset), info, 1, 1, 0, opline
+ }
+ }
+ return 1;
+}
+
+static int zend_jit_leave_func(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa)
+{
+ // Avoid multiple leave sequences
+ if (jit_return_label >= 0) {
+ | jmp =>jit_return_label
+ return 1;
+ }
+
+ jit_return_label = ssa->cfg.blocks_count * 2;
+
+ |=>jit_return_label:
+
+ | // EG(current_execute_data) = EX(prev_execute_data);
+ | mov r0, EX->prev_execute_data
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, current_execute_data, r0, r2
+
+ // i_free_compiled_variables(execute_data);
+ if (!zend_jit_free_compiled_variables(Dst, opline, op_array, ssa)) {
+ return 0;
+ }
+
+ /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
+ | mov FCARG1d, dword [FP + offsetof(zend_execute_data, This.u1.type_info)]
+ | test FCARG1d, (ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_FAKE_CLOSURE)
+ | jnz ->leave_function_handler
+
+ if ((op_array->scope && !(op_array->fn_flags & ZEND_ACC_STATIC)) ||
+ (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
+ if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
+ | // OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
+ | mov r0, EX->func
+ | sub r0, sizeof(zend_object)
+ | OBJ_RELEASE r0, ecx, >4
+ } else if (op_array->scope && !(op_array->fn_flags & ZEND_ACC_STATIC)) {
+ | // if (call_info & ZEND_CALL_RELEASE_THIS)
+ | test FCARG1d, ZEND_CALL_RELEASE_THIS
+ | je >4
+ | // zend_object *object = Z_OBJ(execute_data->This);
+ | mov r0, EX->This.value.obj
+ | // OBJ_RELEASE(object);
+ | OBJ_RELEASE r0, ecx, >4
+ }
+ |4:
+ }
+ | // EG(vm_stack_top) = (zval*)execute_data;
+ | MEM_OP2_1_ZTS mov, aword, executor_globals, vm_stack_top, FP, r0
+ | // execute_data = EX(prev_execute_data);
+ | mov FP, EX->prev_execute_data
+ | // if (EG(exception))
+ | MEM_OP2_1_ZTS cmp, aword, executor_globals, exception, 0, r0
+ | LOAD_OPLINE
+ | jne ->leave_throw_handler
+ | // opline = EX(opline) + 1
+ | ADD_IP sizeof(zend_op)
+ if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
+ | add r4, HYBRID_SPAD
+#ifdef CONTEXT_THREADED_JIT
+ | push aword [IP]
+ | ret
+#else
+ | JMP_IP
+#endif
+ } else if (GCC_GLOBAL_REGS) {
+ | add r4, SPAD // stack alignment
+#ifdef CONTEXT_THREADED_JIT
+ | push aword [IP]
+ | ret
+#else
+ | JMP_IP
+#endif
+ } else {
+#ifdef CONTEXT_THREADED_JIT
+ ZEND_ASSERT(0);
+ // TODO: context threading can't work without GLOBAL REGS because we have to change
+ // the value of execute_data in execute_ex()
+ | mov FCARG1a, FP
+ | mov r0, aword [FP]
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ | push aword [r0]
+ | ret
+#else
+ | mov FP, aword T2 // restore FP
+ | mov RX, aword T3 // restore IP
+ | add r4, NR_SPAD // stack alignment
+ | mov r0, 2 // ZEND_VM_LEAVE
+ | ret
+#endif
+ }
+
+ return 1;
+}
+
+static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, uint32_t op1_info, zend_jit_addr op1_addr)
+{
+ zend_jit_addr ret_addr;
+
+ ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
+ ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
+
+ // if (!EX(return_value))
+ if (Z_MODE(op1_addr) == IS_REG && Z_REG(op1_addr) == ZREG_R1) {
+ | mov r2, EX->return_value
+ | test r2, r2
+ ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R2, 0);
+ } else {
+ | mov r1, EX->return_value
+ | test r1, r1
+ ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R1, 0);
+ }
+ if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
+ (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ | jz >1
+ |.cold_code
+ |1:
+ if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ if (jit_return_label >= 0) {
+ | IF_NOT_ZVAL_REFCOUNTED op1_addr, =>jit_return_label
+ } else {
+ | IF_NOT_ZVAL_REFCOUNTED op1_addr, >9
+ }
+ }
+ | GET_ZVAL_PTR FCARG1a, op1_addr
+ | GC_DELREF FCARG1a
+ if (RC_MAY_BE_1(op1_info)) {
+ if (RC_MAY_BE_N(op1_info)) {
+ if (jit_return_label >= 0) {
+ | jnz =>jit_return_label
+ } else {
+ | jnz >9
+ }
+ }
+ | //SAVE_OPLINE()
+ | ZVAL_DTOR_FUNC op1_info, opline
+ | //????mov r1, EX->return_value // reload ???
+ }
+ if (jit_return_label >= 0) {
+ | jmp =>jit_return_label
+ } else {
+ | jmp >9
+ }
+ |.code
+ } else {
+ if (jit_return_label >= 0) {
+ | jz =>jit_return_label
+ } else {
+ | jz >9
+ }
+ }
+
+ if (opline->op1_type == IS_CONST) {
+ zval *zv = RT_CONSTANT(opline, opline->op1);
+ | ZVAL_COPY_CONST ret_addr, -1, -1, zv, r0
+ if (Z_REFCOUNTED_P(zv)) {
+ | ADDREF_CONST zv, r0
+ }
+ } else if (opline->op1_type == IS_TMP_VAR) {
+ | ZVAL_COPY_VALUE ret_addr, -1, op1_addr, op1_info, ZREG_R0, ZREG_R2
+ } else if (opline->op1_type == IS_CV) {
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR r0, op1_addr
+ | ZVAL_DEREF r0, op1_info
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
+ }
+ | ZVAL_COPY_VALUE ret_addr, -1, op1_addr, op1_info, ZREG_R0, ZREG_R2
+ | // TODO: JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr); ???
+ | TRY_ADDREF op1_info, ah, r2
+ } else {
+ if (op1_info & MAY_BE_REF) {
+ zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, offsetof(zend_reference, val));
+
+ | IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1
+ |.cold_code
+ |1:
+ | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
+ | GET_ZVAL_PTR r0, op1_addr
+ | // ZVAL_COPY_VALUE(return_value, &ref->value);
+ | ZVAL_COPY_VALUE ret_addr, -1, ref_addr, op1_info, ZREG_R2, ZREG_R2
+ | GC_DELREF r0
+ | je >2
+ | // if (IS_REFCOUNTED())
+ if (jit_return_label >= 0) {
+ | IF_NOT_REFCOUNTED dh, =>jit_return_label
+ } else {
+ | IF_NOT_REFCOUNTED dh, >9
+ }
+ | // ADDREF
+ | GET_ZVAL_PTR r2, ret_addr // reload
+ | GC_ADDREF r2
+ if (jit_return_label >= 0) {
+ | jmp =>jit_return_label
+ } else {
+ | jmp >9
+ }
+ |2:
+ | EFREE_24 r0, op_array, opline
+ if (jit_return_label >= 0) {
+ | jmp =>jit_return_label
+ } else {
+ | jmp >9
+ }
+ |.code
+ }
+ | ZVAL_COPY_VALUE ret_addr, -1, op1_addr, op1_info, ZREG_R0, ZREG_R2
+ }
+
+ |9:
+ //JIT: ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
+ return zend_jit_leave_func(Dst, opline, op_array, ssa);
+}
+
+static int zend_jit_fetch_dim_read(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op2_info, uint32_t res_info, int may_throw)
+{
+ zend_jit_addr op1_addr, orig_op1_addr, op2_addr, res_addr;
+
+ op1_addr = orig_op1_addr = OP1_ADDR();
+ op2_addr = OP2_ADDR();
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | ZVAL_DEREF FCARG1a, op1_info
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ }
+
+ if (op1_info & MAY_BE_ARRAY) {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
+ }
+ | GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode == ZEND_FETCH_DIM_R) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, 8, 9)) {
+ return 0;
+ }
+ }
+
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
+ if (op1_info & MAY_BE_ARRAY) {
+ |.cold_code
+ |7:
+ }
+
+ if (op1_info & MAY_BE_STRING) {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6
+ }
+ | SAVE_VALID_OPLINE opline
+ if (Z_REG(op1_addr) != ZREG_FCARG1a) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, res_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR res_addr, r0
+ |.endif
+ if (opline->opcode == ZEND_FETCH_DIM_R) {
+ | EXT_CALL zend_jit_fetch_dim_str_r_helper, r0
+ } else if (opline->opcode == ZEND_FETCH_DIM_IS) {
+ | EXT_CALL zend_jit_fetch_dim_str_is_helper, r0
+ } else {
+ ZEND_ASSERT(0);
+ }
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ if ((op1_info & MAY_BE_ARRAY) ||
+ (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING)))) {
+ | jmp >9 // END
+ }
+ |6:
+ }
+
+ if (op1_info & MAY_BE_OBJECT) {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_OBJECT))) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >6
+ }
+ | SAVE_VALID_OPLINE opline
+ if (Z_REG(op1_addr) != ZREG_FCARG1a) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
+ ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
+ | LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
+ } else {
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ }
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, res_addr
+ |.else
+ | sub r4, 12
+ | PUSH_ZVAL_ADDR res_addr, r0
+ |.endif
+ if (opline->opcode == ZEND_FETCH_DIM_R) {
+ | EXT_CALL zend_jit_fetch_dim_obj_r_helper, r0
+ } else if (opline->opcode == ZEND_FETCH_DIM_IS) {
+ | EXT_CALL zend_jit_fetch_dim_obj_is_helper, r0
+ } else {
+ ZEND_ASSERT(0);
+ }
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ if ((op1_info & MAY_BE_ARRAY) ||
+ (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_OBJECT)))) {
+ | jmp >9 // END
+ }
+ |6:
+ }
+
+ if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
+ | SAVE_VALID_OPLINE opline
+ if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
+ | // zend_error(E_WARNING, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var))));
+ | mov FCARG1d, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ |1:
+ }
+
+ if (op2_info & MAY_BE_UNDEF) {
+ | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1
+ | mov FCARG1d, opline->op2.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ |1:
+ }
+ }
+
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_OBJECT))) {
+ if (opline->opcode != ZEND_FETCH_DIM_IS) {
+ | SAVE_VALID_OPLINE opline
+ | LOAD_ZVAL_ADDR FCARG1a, orig_op1_addr
+ | EXT_CALL zend_jit_invalid_array_access, r0
+ }
+ | SET_ZVAL_TYPE_INFO res_addr, IS_NULL
+ if (op1_info & MAY_BE_ARRAY) {
+ | jmp >9 // END
+ }
+ }
+
+ if (op1_info & MAY_BE_ARRAY) {
+ |.code
+ }
+ }
+
+ if (op1_info & MAY_BE_ARRAY) {
+ zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
+
+ |8:
+ if (op1_info & MAY_BE_ARRAY_OF_REF) {
+ | // ZVAL_COPY_DEREF
+ | IF_NOT_ZVAL_REFCOUNTED val_addr, >2
+ | IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, >1
+ | GET_Z_PTR r0, r0
+ | add r0, offsetof(zend_reference, val)
+ | IF_NOT_ZVAL_REFCOUNTED val_addr, >2
+ |1:
+ | GET_Z_PTR r1, r0
+ | GC_ADDREF r1
+ |2:
+ | ZVAL_COPY_VALUE res_addr, -1, val_addr, MAY_BE_ANY, ZREG_R1, ZREG_R2
+ } else {
+ | // ZVAL_COPY
+ | ZVAL_COPY_VALUE res_addr, -1, val_addr, MAY_BE_ANY, ZREG_R1, ZREG_R2
+ | TRY_ADDREF res_info, ch, r2
+ }
+ }
+ |9: // END
+
+#ifdef ZEND_JIT_USE_RC_INFERENCE
+ if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
+ /* Magic offsetGet() may increase refcount of the key */
+ op2_info |= MAY_BE_RCN;
+ }
+#endif
+
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
+
+ if (may_throw) {
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_isset_isempty_dim(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, uint32_t op2_info, int may_throw, zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2)
+{
+ zend_jit_addr op1_addr, op2_addr, res_addr;
+
+ // TODO: support for empty() ???
+ ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
+
+ op1_addr = OP1_ADDR();
+ op2_addr = OP2_ADDR();
+ res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | ZVAL_DEREF FCARG1a, op1_info
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ }
+
+ if (op1_info & MAY_BE_ARRAY) {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7
+ }
+ | GET_ZVAL_LVAL ZREG_FCARG1a, op1_addr
+ if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_JIT_IS, op1_info, op2_info, 8, 9)) {
+ return 0;
+ }
+ }
+
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
+ if (op1_info & MAY_BE_ARRAY) {
+ |.cold_code
+ |7:
+ }
+
+ | SAVE_VALID_OPLINE opline
+ if (Z_REG(op1_addr) != ZREG_FCARG1a) {
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ }
+ if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
+ ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
+ | LOAD_ADDR FCARG2a, (Z_ZV(op2_addr) + 1)
+ } else {
+ | LOAD_ZVAL_ADDR FCARG2a, op2_addr
+ }
+ | EXT_CALL zend_jit_isset_dim_helper, r0
+ | test r0, r0
+ | jz >9
+ | jmp >8
+
+ if (op1_info & MAY_BE_ARRAY) {
+ |.code
+ }
+ }
+
+#ifdef ZEND_JIT_USE_RC_INFERENCE
+ if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
+ /* Magic offsetExists() may increase refcount of the key */
+ op2_info |= MAY_BE_RCN;
+ }
+#endif
+
+ |8:
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
+ if (may_throw) {
+ if (!zend_jit_check_exception_undef_result(Dst, opline)) {
+ return 0;
+ }
+ }
+ if (!(opline->extended_value & ZEND_ISEMPTY)) {
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ | jmp =>target_label2
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ | jmp =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ | jmp =>target_label2
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+ | jmp >8
+ }
+ } else {
+ | //????
+ | int3
+ }
+
+ |9: // not found
+ | FREE_OP opline->op2_type, opline->op2, op2_info, 0, op_array, opline
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 0, op_array, opline
+ if (may_throw) {
+ if (!zend_jit_check_exception_undef_result(Dst, opline)) {
+ return 0;
+ }
+ }
+ if (!(opline->extended_value & ZEND_ISEMPTY)) {
+ if (smart_branch_opcode) {
+ if (smart_branch_opcode == ZEND_JMPZ) {
+ | jmp =>target_label
+ } else if (smart_branch_opcode == ZEND_JMPNZ) {
+ } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+ | jmp =>target_label
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+ }
+ } else {
+ | //????
+ | int3
+ }
+
+ |8:
+
+ return 1;
+}
+
+static int zend_jit_bind_global(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
+{
+ zend_jit_addr op1_addr = OP1_ADDR();
+ zval *varname = RT_CONSTANT(opline, opline->op2);
+
+ //idx = (uint32_t)(uintptr_t)CACHED_PTR(opline->extended_value) - 1;
+ | mov r0, EX->run_time_cache
+ | mov r0, aword [r0 + opline->extended_value]
+ | sub r0, 1
+ //if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
+ |.if X64
+ | MEM_OP2_2_ZTS movsxd, r1, dword, executor_globals, symbol_table.nNumUsed, r1
+ | shl r1, 5
+ |.else
+ | MEM_OP2_2_ZTS mov, r1, dword, executor_globals, symbol_table.nNumUsed, r1
+ | imul r1, sizeof(Bucket)
+ |.endif
+ | cmp r0, r1
+ | jae >9
+ //Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
+ | MEM_OP2_2_ZTS add, r0, aword, executor_globals, symbol_table.arData, r1
+ | IF_Z_TYPE r0, IS_UNDEF, >9
+ // (EXPECTED(p->key == Z_STR_P(varname))
+ | ADDR_OP2_2 cmp, aword [r0 + offsetof(Bucket, key)], Z_PTR_P(varname), r1
+ | jne >1
+ |.cold_code
+ |1:
+ //(EXPECTED(p->h == ZSTR_H(Z_STR_P(varname)))
+ | ADDR_OP2_2 cmp, aword [r0 + offsetof(Bucket, h)], ZSTR_H(Z_STR_P(varname)), r1
+ | jne >9
+ //EXPECTED(p->key != NULL)
+ | mov r1, [r0 + offsetof(Bucket, key)]
+ | test r1, r1
+ | jz >9
+ //EXPECTED(ZSTR_LEN(p->key) == Z_STRLEN_P(varname))
+ | ADDR_OP2_2 cmp, aword [r1 + offsetof(zend_string, len)], Z_STRLEN_P(varname), r2
+ | jne >9
+ //EXPECTED(memcmp(ZSTR_VAL(p->key), Z_STRVAL_P(varname), Z_STRLEN_P(varname)) == 0)
+ | add r1, offsetof(zend_string, val)
+ | mov T1, r0
+ |.if X64
+ | mov CARG1, r1
+ | LOAD_ADDR CARG2, Z_STRVAL_P(varname)
+ | mov CARG3, Z_STRLEN_P(varname)
+ | EXT_CALL memcmp, r0
+ |.else
+ | sub r4, 4
+ | push Z_STRLEN_P(varname)
+ | push Z_STRVAL_P(varname)
+ | push r1
+ | call &memcmp
+ | add r4, 16
+ |.endif
+ | test al, al
+ | mov r0, aword T1
+ | jnz >9
+ | jmp >2
+ |.code
+ |2:
+ // if (UNEXPECTED(Z_TYPE_P(value) == IS_INDIRECT))
+ | mov cl, byte [r0 + 8]
+ | cmp cl, IS_INDIRECT
+ | je >1
+ |.cold_code
+ |1:
+ //value = Z_INDIRECT_P(value)
+ | mov r0, [r0]
+ | mov cl, byte [r0 + 8]
+ | test cl, cl // cmp cl, IS_UNDEF
+ | jne >2
+ | SET_Z_TYPE_INFO r0, IS_NULL
+ |.code
+ |2:
+ | cmp cl, IS_REFERENCE
+ | jne >8
+ |1:
+ if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
+ //stash this for later use
+ | mov r2, r0
+ }
+ | GET_Z_PTR r0, r0
+ | GC_ADDREF r0
+ //if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
+ if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
+ if (op1_info & (MAY_BE_ANY - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
+ | IF_ZVAL_REFCOUNTED op1_addr, >2
+ }
+ |.cold_code
+ //zval_dtor_func(Z_COUNTED_P(variable_ptr))
+ |2:
+ //if (EXPECTED(variable_ptr != value))
+ | LOAD_ZVAL_ADDR FCARG1a, op1_addr
+ | cmp FCARG1a, r2
+ | je >4
+ | GET_Z_PTR FCARG1a, FCARG1a
+ | GC_DELREF FCARG1a
+ if (op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
+ | jnz >3
+ }
+ | mov aword T1, r0 // save
+ | ZVAL_DTOR_FUNC op1_info, opline
+ | mov r0, aword T1 // restore
+ | jmp >5
+ if (op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
+ |3:
+ // GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
+ | IF_GC_MAY_NOT_LEAK FCARG1a, edx, >5
+ | mov aword T1, r0 //save
+ | EXT_CALL gc_possible_root, r1
+ | mov r0, aword T1 // restore
+ | jmp >5
+ }
+ |4:
+ | GET_Z_PTR FCARG1a, FCARG1a
+ | GC_DELREF FCARG1a
+ | jmp >5
+ |.code
+ }
+ |5:
+ //ZVAL_REF(variable_ptr, ref)
+ | SET_ZVAL_PTR op1_addr, r0
+ | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX
+ //END of handler
+
+ |.cold_code
+ |8:
+ | mov FCARG1a, r0
+ | EXT_CALL zend_jit_new_ref_helper, r0
+ | jmp <1
+ |9:
+ | mov FCARG1a, FP
+ | LOAD_ADDR FCARG2a, (ptrdiff_t)varname
+ |.if X64
+ | mov CARG3, opline->extended_value
+ |.else
+ | sub r4, 12
+ | push opline->extended_value
+ |.endif
+ | EXT_CALL zend_jit_fetch_global_helper, r0
+ |.if not(X64)
+ | add r4, 12
+ |.endif
+ | jmp <1
+ |.code
+
+ return 1;
+}
+
+static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array)
+{
+ uint32_t arg_num = opline->op1.num;
+
+ | cmp dword EX->This.u2.num_args, arg_num
+ | jb >1
+ |.cold_code
+ |1:
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1a, FP
+ | EXT_CALL zend_missing_arg_error, r0
+ | jmp ->exception_handler
+ |.code
+
+ if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+ zend_arg_info *arg_info = NULL;
+
+ if (EXPECTED(arg_num <= op_array->num_args)) {
+ arg_info = &op_array->arg_info[arg_num-1];
+ } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
+ arg_info = &op_array->arg_info[op_array->num_args];
+ }
+ if (arg_info) {
+ zend_type type = arg_info->type;
+
+ if (ZEND_TYPE_IS_SET(type)) {
+ // Type check
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ | LOAD_ZVAL_ADDR r0, res_addr
+ if (ZEND_ARG_SEND_MODE(arg_info)) {
+ | GET_Z_PTR r0, r0
+ | add r0, offsetof(zend_reference, val)
+ }
+
+ uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
+ if (type_mask == 0) {
+ | jmp >8
+ } else if (is_power_of_two(type_mask)) {
+ uint32_t type_code = concrete_type(type_mask);
+ | cmp byte [r0 + 8], type_code
+ | jne >8
+ } else {
+ | mov edx, 1
+ | mov cl, byte [r0 + 8]
+ | shl edx, cl
+ | test edx, type_mask
+ | je >8
+ }
+
+ |.cold_code
+ |8:
+ | SAVE_VALID_OPLINE opline
+ | mov FCARG1a, r0
+ | mov r0, EX->run_time_cache
+ | add r0, opline->extended_value
+ | mov FCARG2a, EX->func
+ |.if X64WIN
+ | mov CARG3, arg_num
+ | LOAD_ADDR CARG4, (ptrdiff_t)arg_info
+ | mov aword A5, r0
+ | EXT_CALL zend_jit_verify_arg_slow, r0
+ |.elif X64
+ | mov CARG3, arg_num
+ | LOAD_ADDR CARG4, (ptrdiff_t)arg_info
+ | mov CARG5, r0
+ | EXT_CALL zend_jit_verify_arg_slow, r0
+ |.else
+ | sub r4, 4
+ | push r0
+ | push (ptrdiff_t)arg_info
+ | push arg_num
+ | EXT_CALL zend_jit_verify_arg_slow, r0
+ | add r4, 4
+ |.endif
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ | jmp >1
+ |.code
+ |1:
+
+ if ((opline+1)->opcode != ZEND_RECV && (opline+1)->opcode != ZEND_RECV_INIT) {
+ last_valid_opline = NULL;
+ if (!zend_jit_set_valid_ip(Dst, opline + 1)) {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+ }
+ }
+
+ if ((opline+1)->opcode != ZEND_RECV && (opline+1)->opcode != ZEND_RECV_INIT) {
+ last_valid_opline = NULL;
+ if (!zend_jit_set_valid_ip(Dst, opline + 1)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_bool is_last, int may_throw)
+{
+ zend_arg_info *arg_info = NULL;
+ zend_bool has_slow = 0;
+ uint32_t arg_num = opline->op1.num;
+ zval *zv = RT_CONSTANT(opline, opline->op2);
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+ | cmp dword EX->This.u2.num_args, arg_num
+ | jae >5
+ | ZVAL_COPY_CONST res_addr, -1, -1, zv, r0
+ if (Z_REFCOUNTED_P(zv)) {
+ | ADDREF_CONST zv, r0
+ }
+ if (Z_CONSTANT_P(zv)) {
+ has_slow = 1;
+ | SAVE_VALID_OPLINE opline
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG1, res_addr
+ | mov r0, EX->func
+ | mov CARG2, [r0 + offsetof(zend_op_array, scope)]
+ | EXT_CALL zval_update_constant_ex, r0
+ |.else
+ | sub r4, 8
+ | mov r0, EX->func
+ | push dword [r0 + offsetof(zend_op_array, scope)]
+ | LOAD_ZVAL_ADDR r0, res_addr
+ | push r0
+ | EXT_CALL zval_update_constant_ex, r0
+ | add r4, 16
+ |.endif
+ | test al, al
+ | jnz >7
+ }
+ |5:
+ if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+ do {
+ if (arg_num <= op_array->num_args) {
+ arg_info = &op_array->arg_info[arg_num-1];
+ } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
+ arg_info = &op_array->arg_info[op_array->num_args];
+ } else {
+ break;
+ }
+ if (!ZEND_TYPE_IS_SET(arg_info->type)) {
+ break;
+ }
+ has_slow += 2;
+ | LOAD_ZVAL_ADDR r0, res_addr
+ | ZVAL_DEREF r0, MAY_BE_REF
+
+ uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type);
+ if (type_mask == 0) {
+ | jmp >8
+ } else if (is_power_of_two(type_mask)) {
+ uint32_t type_code = concrete_type(type_mask);
+ | cmp byte [r0 + 8], type_code
+ | jne >8
+ } else {
+ | mov edx, 1
+ | mov cl, byte [r0 + 8]
+ | shl edx, cl
+ | test edx, type_mask
+ | je >8
+ }
+ } while (0);
+ }
+ |9:
+ if (may_throw) {
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ }
+ if (is_last) {
+ | LOAD_IP_ADDR (opline + 1)
+ last_valid_opline = (opline + 1);
+ }
+
+ if (has_slow) {
+ |.cold_code
+ if (has_slow & 1) {
+ |7:
+ | ZVAL_PTR_DTOR res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, 0, 0, opline
+ | SET_ZVAL_TYPE_INFO res_addr, IS_UNDEF
+ if (may_throw) {
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ }
+ | jmp <5
+ }
+ if (has_slow & 2) {
+ |8:
+ | mov FCARG1a, r0
+ | mov r0, EX->run_time_cache
+ | lea r0, [r0 + opline->extended_value]
+ | mov FCARG2a, EX->func
+ |.if X64WIN
+ | mov CARG3, arg_num
+ | LOAD_ADDR CARG4, (ptrdiff_t)arg_info
+ | mov aword A5, r0
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_verify_arg_slow, r0
+ |.elif X64
+ | mov CARG3, arg_num
+ | LOAD_ADDR CARG4, (ptrdiff_t)arg_info
+ | mov CARG5, r0
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_verify_arg_slow, r0
+ |.else
+ | sub r4, 4
+ | push r0
+ | push (ptrdiff_t)arg_info
+ | push arg_num
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_verify_arg_slow, r0
+ | add r4, 4
+ |.endif
+ | jmp <9
+ }
+ |.code
+ }
+
+ return 1;
+}
+
+#define ZEND_WRONG_PROPERTY_OFFSET 0
+
+static uint32_t zend_get_known_property_offset(zend_class_entry *ce, zend_string *member, zend_bool on_this, zend_string *filename)
+{
+ zend_property_info *info;
+
+ if (!ce || !(ce->ce_flags & ZEND_ACC_LINKED) || (ce->ce_flags & ZEND_ACC_TRAIT)) {
+ return ZEND_WRONG_PROPERTY_OFFSET;
+ }
+
+ if (ce->info.user.filename != filename) {
+ /* class declaration might be changed infdependently */
+ return ZEND_WRONG_PROPERTY_OFFSET;
+ }
+
+ if (ce->parent) {
+ zend_class_entry *parent = ce->parent;
+
+ do {
+ if (parent->type == ZEND_INTERNAL_CLASS) {
+ break;
+ } else if (parent->info.user.filename != filename) {
+ /* some of parents class declarations might be changed infdependently */
+ /* TODO: this check may be not enough, because even
+ * in the same it's possible to conditionally define
+ * few classes with the same name, and "parent" may
+ * change from request to request.
+ */
+ return ZEND_WRONG_PROPERTY_OFFSET;
+ }
+ parent = parent->parent;
+ } while (parent);
+ }
+
+ info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
+ if (info == NULL ||
+ info->offset == ZEND_WRONG_PROPERTY_OFFSET ||
+ (info->flags & ZEND_ACC_STATIC)) {
+ return ZEND_WRONG_PROPERTY_OFFSET;
+ }
+
+ if (!(info->flags & ZEND_ACC_PUBLIC) &&
+ (!on_this || info->ce != ce)) {
+ return ZEND_WRONG_PROPERTY_OFFSET;
+ }
+
+ return info->offset;
+}
+
+static zend_bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string *member, zend_bool on_this, zend_string *filename)
+{
+ zend_property_info *info;
+
+ if (!ce || (ce->ce_flags & ZEND_ACC_TRAIT)) {
+ return 1;
+ }
+
+ if (ce->info.user.filename != filename) {
+ /* class declaration might be changed infdependently */
+ return 1;
+ }
+
+ info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
+ if (info == NULL ||
+ info->offset == ZEND_WRONG_PROPERTY_OFFSET ||
+ (info->flags & ZEND_ACC_STATIC)) {
+ return 1;
+ }
+
+ if (!(info->flags & ZEND_ACC_PUBLIC) &&
+ (!on_this || info->ce != ce)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int zend_jit_fetch_obj_read(dasm_State **Dst, zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_class_entry *ce, int may_throw)
+{
+ zval *member;
+ uint32_t offset;
+ zend_bool may_be_dynamic = 1;
+ zend_jit_addr op1_addr = 0;
+ zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+ zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
+ zend_jit_addr prop_addr;
+
+ ZEND_ASSERT(opline->op2_type == IS_CONST);
+ ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
+
+ member = RT_CONSTANT(opline, opline->op2);
+ ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
+ offset = zend_get_known_property_offset(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
+
+ if (opline->op1_type == IS_UNUSED) {
+ | GET_ZVAL_PTR FCARG1a, this_addr
+ } else {
+ op1_addr = OP1_ADDR();
+ if (op1_info & MAY_BE_REF) {
+ | LOAD_ZVAL_ADDR r0, op1_addr
+ | ZVAL_DEREF r0, op1_info
+ op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0);
+ }
+ if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >7
+ }
+ | GET_ZVAL_PTR FCARG1a, op1_addr
+ }
+
+ if (offset == ZEND_WRONG_PROPERTY_OFFSET) {
+ | mov r0, EX->run_time_cache
+ | mov r2, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)]
+ | cmp r2, aword [FCARG1a + offsetof(zend_object, ce)]
+ | jne >5
+ | mov r0, aword [r0 + (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)]
+ may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename);
+ if (may_be_dynamic) {
+ | test r0, r0
+ | jl >8 // dynamic property
+ }
+ | mov edx, dword [FCARG1a + r0 + 8]
+ | IF_TYPE dl, IS_UNDEF, >5
+ | add FCARG1a, r0
+ prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+ } else {
+ prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, offset);
+ | mov edx, dword [FCARG1a + offset + 8]
+ | IF_TYPE dl, IS_UNDEF, >5
+ }
+ | GET_ZVAL_PTR r0, prop_addr
+ | IF_NOT_REFCOUNTED dh, >2
+ if (opline->opcode == ZEND_FETCH_OBJ_R || opline->opcode == ZEND_FETCH_OBJ_IS) {
+ | IF_TYPE dl, IS_REFERENCE, >6
+ }
+ |1:
+ | GC_ADDREF r0
+ |2:
+ |.if X64
+ | SET_ZVAL_PTR res_addr, r0
+ |.else
+ | SET_ZVAL_PTR res_addr, r0
+ | GET_ZVAL_W2 r0, prop_addr
+ | SET_ZVAL_W2 res_addr, r0
+ |.endif
+ | SET_ZVAL_TYPE_INFO res_addr, edx
+
+ |.cold_code
+ |5:
+ | LOAD_ADDR FCARG2a, member
+ |.if X64
+ | LOAD_ZVAL_ADDR CARG3, res_addr
+ | mov CARG4, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)
+ |.else
+ | sub r4, 8
+ | push (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)
+ | PUSH_ZVAL_ADDR res_addr, r0
+ |.endif
+ | SAVE_VALID_OPLINE opline
+ if (opline->opcode == ZEND_FETCH_OBJ_R) {
+ | EXT_CALL zend_jit_fetch_obj_r_slow, r0
+ } else if (opline->opcode == ZEND_FETCH_OBJ_IS) {
+ | EXT_CALL zend_jit_fetch_obj_is_slow, r0
+ } else {
+ ZEND_ASSERT(0);
+ }
+ |.if not(X64)
+ | add r4, 8
+ |.endif
+ | jmp >9
+
+ if (opline->opcode == ZEND_FETCH_OBJ_R || opline->opcode == ZEND_FETCH_OBJ_IS) {
+ |6:
+ if (offset == ZEND_WRONG_PROPERTY_OFFSET) {
+ | mov FCARG2a, FCARG1a
+ } else {
+ | lea FCARG2a, [FCARG1a + offset]
+ }
+ | LOAD_ZVAL_ADDR FCARG1a, res_addr
+ | EXT_CALL zend_jit_zval_copy_deref_helper, r0
+ | jmp >9
+ }
+
+ if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)- MAY_BE_OBJECT)) {
+ |7:
+ if (opline->opcode == ZEND_FETCH_OBJ_R) {
+ | SAVE_VALID_OPLINE opline
+ if (op1_info & MAY_BE_UNDEF) {
+ if (op1_info & MAY_BE_ANY) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1
+ }
+ | mov FCARG1d, opline->op1.var
+ | EXT_CALL zend_jit_undefined_op_helper, r0
+ |1:
+ }
+ |.if X64
+ | mov CARG1, E_WARNING
+ | LOAD_ADDR CARG2, "Trying to get property '%s' of non-object"
+ | LOAD_ADDR CARG3, Z_STRVAL_P(member)
+ | EXT_CALL zend_error, r0
+ |.else
+ | sub r4, 4
+ | push Z_STRVAL_P(member)
+ | push "Trying to get property '%s' of non-object"
+ | push E_WARNING
+ | EXT_CALL zend_error, r0
+ | add r4, 16
+ |.endif
+ }
+ | SET_ZVAL_TYPE_INFO res_addr, IS_NULL
+ | jmp >9
+ }
+
+ if (offset == ZEND_WRONG_PROPERTY_OFFSET && may_be_dynamic) {
+ |8:
+ | mov FCARG2a, r0
+ |.if X64WIN
+ | LOAD_ADDR CARG3, member
+ | LOAD_ZVAL_ADDR CARG4, res_addr
+ | mov aword A5, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)
+ |.elif X64
+ | LOAD_ADDR CARG3, member
+ | LOAD_ZVAL_ADDR CARG4, res_addr
+ | mov CARG5, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)
+ |.else
+ | sub r4, 4
+ | push (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS)
+ | PUSH_ZVAL_ADDR res_addr, r0
+ | PUSH_ADDR member, r0
+ |.endif
+ | SAVE_VALID_OPLINE opline
+ if (opline->opcode == ZEND_FETCH_OBJ_R) {
+ | EXT_CALL zend_jit_fetch_obj_r_dynamic, r0
+ } else if (opline->opcode == ZEND_FETCH_OBJ_IS) {
+ | EXT_CALL zend_jit_fetch_obj_is_dynamic, r0
+ }
+ |.if not(X64)
+ | add r4, 4
+ |.endif
+ | jmp >9
+ }
+
+ |.code;
+ |9: // END
+ | FREE_OP opline->op1_type, opline->op1, op1_info, 1, op_array, opline
+
+ if (may_throw) {
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_free(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int may_throw)
+{
+ zend_jit_addr op1_addr = OP1_ADDR();
+
+ if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
+ if (may_throw) {
+ | SAVE_VALID_OPLINE, opline
+ }
+ if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
+ if (op1_info & MAY_BE_ARRAY) {
+ | IF_ZVAL_TYPE op1_addr, IS_ARRAY, >7
+ }
+ | mov FCARG1d, dword [FP + opline->op1.var + offsetof(zval, u2.fe_iter_idx)]
+ | cmp FCARG1d, -1
+ | je >7
+ | EXT_CALL zend_hash_iterator_del, r0
+ |7:
+ }
+ | ZVAL_PTR_DTOR op1_addr, op1_info, 0, 0, 0, opline
+ if (may_throw) {
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int zend_jit_echo(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array)
+{
+ zval *zv;
+ size_t len;
+
+ ZEND_ASSERT(opline->op1_type == IS_CONST);
+ zv = RT_CONSTANT(opline, opline->op1);
+ ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
+ len = Z_STRLEN_P(zv);
+
+ if (len > 0) {
+ const char *str = Z_STRVAL_P(zv);
+
+ | SAVE_VALID_OPLINE opline
+ |.if X64
+ | LOAD_ADDR CARG1, str
+ | LOAD_ADDR CARG2, len
+ | EXT_CALL zend_write, r0
+ |.else
+ | sub r4, 8
+ | push len
+ | push str
+ | EXT_CALL zend_write, r0
+ | add r4, 16
+ |.endif
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa)
+{
+ HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
+
+ if (sizeof(void*) == 8 && !IS_32BIT(dasm_end)) {
+ // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ return 1;
+ }
+ if (opline->op1_type == IS_CONST) {
+ zval *zv = RT_CONSTANT(opline, opline->op1);
+ zval *jump_zv;
+ int b;
+
+ if (opline->opcode == ZEND_SWITCH_LONG) {
+ if (Z_TYPE_P(zv) == IS_LONG) {
+ jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
+ if (jump_zv != NULL) {
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
+ } else {
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
+ }
+ | jmp =>b
+ }
+ } else if (opline->opcode == ZEND_SWITCH_STRING) {
+ if (Z_TYPE_P(zv) == IS_STRING) {
+ jump_zv = zend_hash_find_ex(jumptable, Z_STR_P(zv), 1);
+ if (jump_zv != NULL) {
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
+ } else {
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
+ }
+ | jmp =>b
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ } else {
+ uint32_t op1_info = OP1_INFO();
+ zend_jit_addr op1_addr = OP1_ADDR();
+ int b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
+ zval *val;
+
+ if (opline->opcode == ZEND_SWITCH_LONG) {
+ if (op1_info & MAY_BE_LONG) {
+ if (op1_info & MAY_BE_REF) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >1
+ | GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr
+ |.cold_code
+ |1:
+ | // ZVAL_DEREF(op)
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
+ | GET_ZVAL_PTR FCARG2a, op1_addr
+ | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_LONG, >3
+ | mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.lval)]
+ | jmp >2
+ |.code
+ |2:
+ } else {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3
+ }
+ | GET_ZVAL_LVAL ZREG_FCARG2a, op1_addr
+ }
+ if (HT_IS_PACKED(jumptable)) {
+ uint32_t count = jumptable->nNumUsed;
+ Bucket *p = jumptable->arData;
+
+ | cmp FCARG2a, jumptable->nNumUsed
+ | jae >3
+ |.if X64
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | movsxd r0, dword [FCARG2a * 4 + >4]
+ | jmp r0
+ |.else
+ | jmp aword [FCARG2a * 4 + >4]
+ |.endif
+ |3:
+ |.cold_code
+ |4:
+ p = jumptable->arData;
+ do {
+ if (Z_TYPE(p->val) == IS_UNDEF) {
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | .aword =>b
+ } else {
+ int b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val)) - op_array->opcodes];
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | .aword =>b
+ }
+ p++;
+ count--;
+ } while (count);
+ |.code
+ } else {
+ | LOAD_ADDR FCARG1a, jumptable
+ | EXT_CALL zend_hash_index_find, r0
+ | test r0, r0
+ | jz =>b
+ | LOAD_ADDR FCARG1a, jumptable
+ | sub r0, aword [FCARG1a + offsetof(HashTable, arData)]
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | mov FCARG1a, (sizeof(Bucket) / sizeof(uint32_t))
+ |.if X64
+ | cqo
+ |.else
+ | cdq
+ |.endif
+ | idiv FCARG1a
+ |.if X64
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | movsxd r0, dword [r0 + >4]
+ | jmp r0
+ |.else
+ | jmp dword [r0 + >4]
+ |.endif
+ |3:
+ |.cold_code
+ |4:
+ ZEND_HASH_FOREACH_VAL(jumptable, val) {
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val)) - op_array->opcodes];
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | .aword =>b
+ } ZEND_HASH_FOREACH_END();
+ |.code
+ }
+ }
+ } else if (opline->opcode == ZEND_SWITCH_STRING) {
+ if (op1_info & MAY_BE_STRING) {
+ if (op1_info & MAY_BE_REF) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >1
+ | GET_ZVAL_PTR FCARG2a, op1_addr
+ |.cold_code
+ |1:
+ | // ZVAL_DEREF(op)
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3
+ | GET_ZVAL_PTR FCARG2a, op1_addr
+ | IF_NOT_Z_TYPE FCARG2a + offsetof(zend_reference, val), IS_STRING, >3
+ | mov FCARG2a, aword [FCARG2a + offsetof(zend_reference, val.value.ptr)]
+ | jmp >2
+ |.code
+ |2:
+ } else {
+ if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
+ | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3
+ }
+ | GET_ZVAL_PTR FCARG2a, op1_addr
+ }
+ | LOAD_ADDR FCARG1a, jumptable
+ | EXT_CALL zend_hash_find, r0
+ | test r0, r0
+ | jz =>b
+ | LOAD_ADDR FCARG1a, jumptable
+ | sub r0, aword [FCARG1a + offsetof(HashTable, arData)]
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | mov FCARG1a, (sizeof(Bucket) / sizeof(uint32_t))
+ |.if X64
+ | cqo
+ |.else
+ | cdq
+ |.endif
+ | idiv FCARG1a
+ |.if X64
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ | movsxd r0, dword [r0 + >4]
+ | jmp r0
+ |.else
+ | jmp dword [r0 + >4]
+ |.endif
+ |3:
+ |.cold_code
+ |4:
+ ZEND_HASH_FOREACH_VAL(jumptable, val) {
+ b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(val)) - op_array->opcodes];
+ | // TODO: DynASM stores .aword as 4-bytes even in 64-bit mode ???
+ |.if X64
+ | .aword =>b
+ |.else
+ | .aword =>b
+ |.endif
+ } ZEND_HASH_FOREACH_END();
+ |.code
+ }
+ } else {
+ ZEND_ASSERT(0);
+ }
+ }
+ return 1;
+}
+
+static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
+{
+ zend_arg_info *arg_info = &op_array->arg_info[-1];
+ ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
+ zend_jit_addr op1_addr = OP1_ADDR();
+
+ | LOAD_ZVAL_ADDR r0, op1_addr
+
+ uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type);
+ if (type_mask == 0) {
+ | jmp >8
+ } else if (is_power_of_two(type_mask)) {
+ uint32_t type_code = concrete_type(type_mask);
+ | cmp byte [r0 + 8], type_code
+ | jne >8
+ } else {
+ | mov edx, 1
+ | mov cl, byte [r0 + 8]
+ | shl edx, cl
+ | test edx, type_mask
+ | je >8
+ }
+ |.cold_code
+ |8:
+ | mov FCARG1a, r0
+ | mov r0, EX->run_time_cache
+ | add r0, opline->op2.num
+ | mov FCARG2a, EX->func
+ |.if X64
+ | LOAD_ADDR CARG3, (ptrdiff_t)arg_info
+ | mov CARG4, r0
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_verify_return_slow, r0
+ |.else
+ | sub r4, 8
+ | push r0
+ | push (ptrdiff_t)arg_info
+ | SAVE_VALID_OPLINE opline
+ | EXT_CALL zend_jit_verify_return_slow, r0
+ | add r4, 8
+ |.endif
+ if (!zend_jit_check_exception(Dst)) {
+ return 0;
+ }
+ | jmp >9
+ |.code
+ |9:
+ return 1;
+}
+
+static zend_bool zend_jit_may_reuse_reg(const zend_op_array *op_array, zend_ssa *ssa, uint32_t position, int def_var, int use_var)
+{
+ if (ssa->var_info[def_var].type != ssa->var_info[use_var].type) {
+ return 0;
+ }
+
+ switch (op_array->opcodes[position].opcode) {
+ case ZEND_QM_ASSIGN:
+ case ZEND_SEND_VAR:
+ case ZEND_ASSIGN:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ return 1;
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ if (def_var == ssa->ops[position].result_def &&
+ use_var == ssa->ops[position].op1_use) {
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static zend_bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, int var)
+{
+ uint32_t op1_info, op2_info;
+
+ switch (opline->opcode) {
+ case ZEND_QM_ASSIGN:
+ case ZEND_SEND_VAR:
+ case ZEND_SEND_VAL:
+ case ZEND_SEND_VAL_EX:
+ case ZEND_IS_SMALLER:
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ case ZEND_CASE:
+ case ZEND_RETURN:
+ return 1;
+ case ZEND_ASSIGN:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ return
+ opline->op1_type == IS_CV &&
+ !(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_RESOURCE|MAY_BE_REF)) &&
+ !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)));
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if ((op1_info | op2_info) & MAY_BE_UNDEF) {
+ return 0;
+ }
+ return (op1_info & op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) != 0;
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ case ZEND_SL:
+ case ZEND_SR:
+ case ZEND_MOD:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if ((op1_info | op2_info) & MAY_BE_UNDEF) {
+ return 0;
+ }
+ return (op1_info & op2_info & MAY_BE_LONG) != 0;
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ op1_info = OP1_INFO();
+ return
+ opline->op1_type == IS_CV &&
+ (op1_info & MAY_BE_LONG);
+ case ZEND_BOOL:
+ case ZEND_BOOL_NOT:
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ return 1;
+ }
+ return 0;
+}
+
+static zend_bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
+{
+ if (ssa->vars[var].no_val) {
+ /* we don't need the value */
+ return 0;
+ }
+
+ if (zend_jit_reg_alloc < ZEND_JIT_REG_ALLOC_GLOBAL) {
+ /* Disable global register allocation,
+ * register allocation forSAA variables connected through Phi functions
+ */
+ if (ssa->vars[var].definition_phi) {
+ return 0;
+ }
+ if (ssa->vars[var].phi_use_chain) {
+ zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
+ do {
+ if (!ssa->vars[phi->ssa_var].no_val) {
+ return 0;
+ }
+ phi = zend_ssa_next_use_phi(ssa, var, phi);
+ } while (phi);
+ }
+ }
+
+ if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
+ ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
+ /* bad type */
+ return 0;
+ }
+
+ if (ssa->vars[var].definition >= 0) {
+ if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + ssa->vars[var].definition, var)) {
+ return 0;
+ }
+ }
+
+ if (ssa->vars[var].use_chain >= 0) {
+ int use = ssa->vars[var].use_chain;
+
+ do {
+ if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
+ !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, var)) {
+ return 0;
+ }
+ use = zend_ssa_next_use(ssa->ops, var, use);
+ } while (use >= 0);
+ }
+
+ return 1;
+}
+
+static zend_bool zend_needs_extra_reg_for_const(const zend_op_array *op_array, const zend_op *opline, zend_uchar op_type, znode_op op)
+{
+|.if X64
+|| if (op_type == IS_CONST) {
+|| zval *zv = RT_CONSTANT(opline, op);
+|| if (Z_TYPE_P(zv) == IS_DOUBLE && Z_DVAL_P(zv) != 0 && !IS_32BIT(zv)) {
+|| return 1;
+|| }
+|| }
+|.endif
+ return 0;
+}
+
+static zend_regset zend_jit_get_scratch_regset(const zend_op_array *op_array, zend_ssa *ssa, uint32_t line, int current_var)
+{
+ const zend_op *opline = op_array->opcodes + line;
+ uint32_t op1_info, op2_info, res_info;
+ zend_regset regset = ZEND_REGSET_SCRATCH;
+
+ switch (opline->opcode) {
+ case ZEND_NOP:
+ case ZEND_OP_DATA:
+ case ZEND_JMP:
+ case ZEND_RETURN:
+ regset = ZEND_REGSET_EMPTY;
+ break;
+ case ZEND_QM_ASSIGN:
+ if (ssa->ops[line].op1_def == current_var ||
+ ssa->ops[line].result_def == current_var) {
+ regset = ZEND_REGSET_EMPTY;
+ break;
+ }
+ /* break missing intentionally */
+ case ZEND_SEND_VAL:
+ case ZEND_SEND_VAL_EX:
+ if (ssa->ops[line].op1_use == current_var) {
+ regset = ZEND_REGSET(ZREG_R0);
+ break;
+ }
+ op1_info = OP1_INFO();
+ if (!(op1_info & MAY_BE_UNDEF)) {
+ if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
+ regset = ZEND_REGSET(ZREG_XMM0);
+ } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
+ regset = ZEND_REGSET(ZREG_R0);
+ } else {
+ regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_R0), ZEND_REGSET(ZREG_R2));
+ }
+ }
+ break;
+ case ZEND_SEND_VAR:
+ if (ssa->ops[line].op1_use == current_var ||
+ ssa->ops[line].op1_def == current_var) {
+ regset = ZEND_REGSET_EMPTY;
+ break;
+ }
+ op1_info = OP1_INFO();
+ if (!(op1_info & MAY_BE_UNDEF)) {
+ if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
+ regset = ZEND_REGSET(ZREG_XMM0);
+ } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
+ } else {
+ regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_R0), ZEND_REGSET(ZREG_R2));
+ if (op1_info & MAY_BE_REF) {
+ ZEND_REGSET_INCL(regset, ZREG_R1);
+ }
+ }
+ }
+ break;
+ case ZEND_ASSIGN:
+ if (ssa->ops[line].op2_use == current_var ||
+ ssa->ops[line].op2_def == current_var ||
+ ssa->ops[line].op1_def == current_var ||
+ ssa->ops[line].result_def == current_var) {
+ regset = ZEND_REGSET_EMPTY;
+ break;
+ }
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if (opline->op1_type == IS_CV
+ && !(op2_info & MAY_BE_UNDEF)
+ && !(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_RESOURCE|MAY_BE_REF))) {
+ if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) {
+ regset = ZEND_REGSET(ZREG_XMM0);
+ } else if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) {
+ regset = ZEND_REGSET(ZREG_R0);
+ } else {
+ regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_R0), ZEND_REGSET(ZREG_R2));
+ }
+ }
+ break;
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ if (ssa->ops[line].op1_use == current_var ||
+ ssa->ops[line].op1_def == current_var ||
+ ssa->ops[line].result_def == current_var) {
+ regset = ZEND_REGSET_EMPTY;
+ break;
+ }
+ op1_info = OP1_INFO();
+ if (opline->op1_type == IS_CV
+ && (op1_info & MAY_BE_LONG)
+ && !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
+ regset = ZEND_REGSET_EMPTY;
+ if (op1_info & MAY_BE_DOUBLE) {
+ regset = ZEND_REGSET(ZREG_XMM0);
+ }
+ }
+ break;
+ case ZEND_ADD:
+ case ZEND_SUB:
+ case ZEND_MUL:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) &&
+ !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
+
+ regset = ZEND_REGSET_EMPTY;
+ if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
+ if (ssa->ops[line].result_def != current_var &&
+ (ssa->ops[line].op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, opline-op_array->opcodes))) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ res_info = OP1_INFO();
+ if (res_info & MAY_BE_DOUBLE) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ ZEND_REGSET_INCL(regset, ZREG_XMM1);
+ }
+ }
+ if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) {
+ if (ssa->ops[line].result_def != current_var) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ }
+ }
+ if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) {
+ if (zend_is_commutative(opline->opcode)) {
+ if (ssa->ops[line].result_def != current_var) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ }
+ } else {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ if (ssa->ops[line].result_def != current_var &&
+ (ssa->ops[line].op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, opline-op_array->opcodes))) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM1);
+ }
+ }
+ }
+ if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) {
+ if (ssa->ops[line].result_def != current_var &&
+ (ssa->ops[line].op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, opline-op_array->opcodes))) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ }
+ }
+ if (zend_needs_extra_reg_for_const(op_array, opline, opline->op1_type, opline->op1) ||
+ zend_needs_extra_reg_for_const(op_array, opline, opline->op1_type, opline->op2)) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ }
+ break;
+ case ZEND_BW_OR:
+ case ZEND_BW_AND:
+ case ZEND_BW_XOR:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
+ !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
+ regset = ZEND_REGSET_EMPTY;
+ if (ssa->ops[line].result_def != current_var &&
+ (ssa->ops[line].op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, opline-op_array->opcodes))) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ }
+ break;
+ case ZEND_SL:
+ case ZEND_SR:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
+ !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
+ regset = ZEND_REGSET_EMPTY;
+ if (ssa->ops[line].result_def != current_var &&
+ (ssa->ops[line].op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, opline-op_array->opcodes))) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ if (opline->op2_type != IS_CONST && ssa->ops[line].op2_use != current_var) {
+ ZEND_REGSET_INCL(regset, ZREG_R1);
+ }
+ }
+ break;
+ case ZEND_MOD:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) &&
+ !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) {
+ regset = ZEND_REGSET_EMPTY;
+ if (opline->op2_type == IS_CONST &&
+ Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG &&
+ zend_long_is_power_of_two(Z_LVAL_P(RT_CONSTANT(opline, opline->op2)))) {
+ if (ssa->ops[line].result_def != current_var &&
+ (ssa->ops[line].op1_use != current_var || !zend_ssa_is_last_use(op_array, ssa, current_var, opline-op_array->opcodes))) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ } else {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ ZEND_REGSET_INCL(regset, ZREG_R1);
+ }
+ }
+ break;
+ case ZEND_IS_SMALLER:
+ case ZEND_IS_SMALLER_OR_EQUAL:
+ case ZEND_IS_EQUAL:
+ case ZEND_IS_NOT_EQUAL:
+ case ZEND_IS_IDENTICAL:
+ case ZEND_IS_NOT_IDENTICAL:
+ case ZEND_CASE:
+ op1_info = OP1_INFO();
+ op2_info = OP2_INFO();
+ if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) &&
+ !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
+ regset = ZEND_REGSET_EMPTY;
+ if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) &&
+ opline->op1_type != IS_CONST && opline->op2_type != IS_CONST) {
+ if (ssa->ops[line].op1_use != current_var &&
+ ssa->ops[line].op2_use != current_var) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ }
+ if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ }
+ if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ }
+ if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) {
+ if (ssa->ops[line].op1_use != current_var &&
+ ssa->ops[line].op2_use != current_var) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ }
+ }
+ if (zend_needs_extra_reg_for_const(op_array, opline, opline->op1_type, opline->op1) ||
+ zend_needs_extra_reg_for_const(op_array, opline, opline->op1_type, opline->op2)) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ }
+ break;
+ case ZEND_BOOL:
+ case ZEND_BOOL_NOT:
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+ op1_info = OP1_INFO();
+ if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)))) {
+ regset = ZEND_REGSET_EMPTY;
+ if (op1_info & MAY_BE_DOUBLE) {
+ ZEND_REGSET_INCL(regset, ZREG_XMM0);
+ }
+ if (opline->opcode == ZEND_BOOL ||
+ opline->opcode == ZEND_BOOL_NOT ||
+ opline->opcode == ZEND_JMPZ_EX ||
+ opline->opcode == ZEND_JMPNZ_EX) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ }
+ break;
+ case ZEND_DO_UCALL:
+ case ZEND_DO_FCALL:
+ case ZEND_DO_FCALL_BY_NAME:
+ case ZEND_INCLUDE_OR_EVAL:
+ case ZEND_GENERATOR_CREATE:
+ case ZEND_YIELD:
+ case ZEND_YIELD_FROM:
+ regset = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP);
+ break;
+ default:
+ break;
+ }
+
+#if ZTS
+ /* %r0 is used to check EG(vm_interrupt) */
+ {
+ uint32_t b = ssa->cfg.map[line];
+
+ if ((ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) != 0
+ && ssa->cfg.blocks[b].start == line) {
+ ZEND_REGSET_INCL(regset, ZREG_R0);
+ }
+ }
+#endif
+
+ return regset;
+}
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ */
diff --git a/ext/opcache/jit/zend_jit_x86.h b/ext/opcache/jit/zend_jit_x86.h
new file mode 100644
index 0000000000..b3806036f6
--- /dev/null
+++ b/ext/opcache/jit/zend_jit_x86.h
@@ -0,0 +1,309 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend JIT |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef HAVE_JIT_X86_H
+#define HAVE_JIT_X86_H
+
+typedef enum _zend_reg {
+ ZREG_NONE = -1,
+
+ ZREG_R0,
+ ZREG_R1,
+ ZREG_R2,
+ ZREG_R3,
+ ZREG_R4,
+ ZREG_R5,
+ ZREG_R6,
+ ZREG_R7,
+
+#if defined(__x86_64__) || defined(_WIN64)
+ ZREG_R8,
+ ZREG_R9,
+ ZREG_R10,
+ ZREG_R11,
+ ZREG_R12,
+ ZREG_R13,
+ ZREG_R14,
+ ZREG_R15,
+#endif
+
+ ZREG_XMM0,
+ ZREG_XMM1,
+ ZREG_XMM2,
+ ZREG_XMM3,
+ ZREG_XMM4,
+ ZREG_XMM5,
+ ZREG_XMM6,
+ ZREG_XMM7,
+
+#if defined(__x86_64__) || defined(_WIN64)
+ ZREG_XMM8,
+ ZREG_XMM9,
+ ZREG_XMM10,
+ ZREG_XMM11,
+ ZREG_XMM12,
+ ZREG_XMM13,
+ ZREG_XMM14,
+ ZREG_XMM15,
+#endif
+
+ ZREG_NUM
+} zend_reg;
+
+#define ZREG_RAX ZREG_R0
+#define ZREG_RCX ZREG_R1
+#define ZREG_RDX ZREG_R2
+#define ZREG_RBX ZREG_R3
+#define ZREG_RSP ZREG_R4
+#define ZREG_RBP ZREG_R5
+#define ZREG_RSI ZREG_R6
+#define ZREG_RDI ZREG_R7
+
+#ifdef _WIN64
+# define ZREG_FP ZREG_R14
+# define ZREG_IP ZREG_R15
+# define ZREG_RX ZREG_IP
+# define ZREG_FCARG1a ZREG_RCX
+# define ZREG_FCARG2a ZREG_RDX
+#elif defined(__x86_64__)
+# define ZREG_FP ZREG_R14
+# define ZREG_IP ZREG_R15
+# define ZREG_RX ZREG_IP
+# define ZREG_FCARG1a ZREG_RDI
+# define ZREG_FCARG2a ZREG_RSI
+#else
+# define ZREG_FP ZREG_RSI
+# define ZREG_IP ZREG_RDI
+# define ZREG_RX ZREG_IP
+# define ZREG_FCARG1a ZREG_RCX
+# define ZREG_FCARG2a ZREG_RDX
+#endif
+
+extern const char *zend_reg_name[];
+
+typedef uint32_t zend_regset;
+
+#define ZEND_REGSET_EMPTY 0
+
+#define ZEND_REGSET_IS_EMPTY(regset) \
+ (regset == ZEND_REGSET_EMPTY)
+
+#define ZEND_REGSET(reg) \
+ (1u << (reg))
+
+#define ZEND_REGSET_INTERVAL(reg1, reg2) \
+ (((1u << ((reg2) - (reg1) + 1)) - 1) << (reg1))
+
+#define ZEND_REGSET_IN(regset, reg) \
+ (((regset) & ZEND_REGSET(reg)) != 0)
+
+#define ZEND_REGSET_INCL(regset, reg) \
+ (regset) |= ZEND_REGSET(reg)
+
+#define ZEND_REGSET_EXCL(regset, reg) \
+ (regset) &= ~ZEND_REGSET(reg)
+
+#define ZEND_REGSET_UNION(set1, set2) \
+ ((set1) | (set2))
+
+#define ZEND_REGSET_INTERSECTION(set1, set2) \
+ ((set1) & (set2))
+
+#define ZEND_REGSET_DIFFERENCE(set1, set2) \
+ ((set1) & ~(set2))
+
+#ifdef _WIN64
+# define ZEND_REGSET_FIXED \
+ (ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_R14) | ZEND_REGSET(ZREG_R15))
+# define ZEND_REGSET_GP \
+ ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R15), ZEND_REGSET_FIXED)
+# define ZEND_REGSET_FP \
+ ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM15), ZEND_REGSET_FIXED)
+# define ZEND_REGSET_SCRATCH \
+ (ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET_INTERVAL(ZREG_R8, ZREG_R11) | ZEND_REGSET_FP)
+# define ZEND_REGSET_PRESERVED \
+ (ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP) | ZEND_REGSET(ZREG_R12) | ZEND_REGSET(ZREG_R13) | ZEND_REGSET(ZREG_RDI) | ZEND_REGSET(ZREG_RSI))
+#elif defined(__x86_64__)
+# define ZEND_REGSET_FIXED \
+ (ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_R14) | ZEND_REGSET(ZREG_R15))
+# define ZEND_REGSET_GP \
+ ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R15), ZEND_REGSET_FIXED)
+# define ZEND_REGSET_FP \
+ ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM15), ZEND_REGSET_FIXED)
+# define ZEND_REGSET_SCRATCH \
+ (ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RDI) | ZEND_REGSET(ZREG_RSI) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET_INTERVAL(ZREG_R8, ZREG_R11) | ZEND_REGSET_FP)
+# define ZEND_REGSET_PRESERVED \
+ (ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP) | ZEND_REGSET(ZREG_R12) | ZEND_REGSET(ZREG_R13))
+#else
+# define ZEND_REGSET_FIXED \
+ (ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_RSI) | ZEND_REGSET(ZREG_RDI))
+# define ZEND_REGSET_GP \
+ ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_R0, ZREG_R7), ZEND_REGSET_FIXED)
+# define ZEND_REGSET_FP \
+ ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_XMM0, ZREG_XMM7), ZEND_REGSET_FIXED)
+# define ZEND_REGSET_SCRATCH \
+ (ZEND_REGSET(ZREG_RAX) | ZEND_REGSET(ZREG_RCX) | ZEND_REGSET(ZREG_RDX) | ZEND_REGSET_FP)
+# define ZEND_REGSET_PRESERVED \
+ (ZEND_REGSET(ZREG_RBX) | ZEND_REGSET(ZREG_RBP))
+#endif
+
+#ifndef _WIN32
+#define ZEND_REGSET_FIRST(set) ((zend_reg)__builtin_ctz(set))
+#define ZEND_REGSET_LAST(set) ((zend_reg)(__builtin_clz(set)^31)))
+#else
+#include <intrin.h>
+uint32_t __inline __zend_jit_ctz( uint32_t value ) {
+ DWORD trailing_zero = 0;
+ if (_BitScanForward(&trailing_zero, value)) {
+ return trailing_zero;
+ }
+ return 32;
+}
+uint32_t __inline __zend_jit_clz(uint32_t value) {
+ DWORD leading_zero = 0;
+ if (_BitScanReverse(&leading_zero, value)) {
+ return 31 - leading_zero;
+ }
+ return 32;
+}
+#define ZEND_REGSET_FIRST(set) ((zend_reg)__zend_jit_ctz(set))
+#define ZEND_REGSET_LAST(set) ((zend_reg)(__zend_jit_clz(set)^31)))
+#endif
+
+#define ZEND_REGSET_FOREACH(set, reg) \
+ do { \
+ zend_regset _tmp = (set); \
+ while (!ZEND_REGSET_IS_EMPTY(_tmp)) { \
+ zend_reg _reg = ZEND_REGSET_FIRST(_tmp); \
+ ZEND_REGSET_EXCL(_tmp, _reg); \
+ reg = _reg; \
+
+#define ZEND_REGSET_FOREACH_END() \
+ } \
+ } while (0)
+
+typedef uintptr_t zend_jit_addr;
+
+#define IS_CONST_ZVAL 0
+#define IS_MEM_ZVAL 1
+#define IS_REG 2
+
+#define _ZEND_ADDR_MODE_MASK 0x3
+#define _ZEND_ADDR_REG_SHIFT 2
+#define _ZEND_ADDR_REG_MASK 0x3f
+#define _ZEND_ADDR_OFFSET_SHIFT 8
+#define _ZEND_ADDR_REG_STORE_BIT 8
+#define _ZEND_ADDR_REG_LOAD_BIT 9
+#define _ZEND_ADDR_REG_LAST_USE_BIT 10
+
+#define ZEND_ADDR_CONST_ZVAL(zv) \
+ (((zend_jit_addr)(uintptr_t)(zv)) | IS_CONST_ZVAL)
+#define ZEND_ADDR_MEM_ZVAL(reg, offset) \
+ ((((zend_jit_addr)(uintptr_t)(offset)) << _ZEND_ADDR_OFFSET_SHIFT) | \
+ (((zend_jit_addr)(uintptr_t)(reg)) << _ZEND_ADDR_REG_SHIFT) | \
+ IS_MEM_ZVAL)
+#define ZEND_ADDR_REG(reg) \
+ ((((zend_jit_addr)(uintptr_t)(reg)) << _ZEND_ADDR_REG_SHIFT) | \
+ IS_REG)
+
+#define Z_MODE(addr) (((addr) & _ZEND_ADDR_MODE_MASK))
+#define Z_ZV(addr) ((zval*)(addr))
+#define Z_OFFSET(addr) ((uint32_t)((addr)>>_ZEND_ADDR_OFFSET_SHIFT))
+#define Z_REG(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_SHIFT) & _ZEND_ADDR_REG_MASK))
+#define Z_STORE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_STORE_BIT) & 1))
+#define Z_LOAD(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LOAD_BIT) & 1))
+#define Z_LAST_USE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LAST_USE_BIT) & 1))
+
+#define OP_REG_EX(reg, store, load, last_use) \
+ ((reg) | \
+ ((store) ? (1 << (_ZEND_ADDR_REG_STORE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \
+ ((load) ? (1 << (_ZEND_ADDR_REG_LOAD_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \
+ ((last_use) ? (1 << (_ZEND_ADDR_REG_LAST_USE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) \
+ )
+
+#define OP_REG(line, op) \
+ (ra && ssa->ops[line].op >= 0 && ra[ssa->ops[line].op] ? \
+ OP_REG_EX(ra[ssa->ops[line].op]->reg, \
+ ra[ssa->ops[line].op]->store, \
+ ra[ssa->ops[line].op]->load, \
+ zend_ssa_is_last_use(op_array, ssa, ssa->ops[line].op, line) \
+ ) : ZREG_NONE)
+
+static zend_always_inline zend_jit_addr _zend_jit_decode_op(zend_uchar op_type, znode_op op, const zend_op *opline, zend_reg reg)
+{
+ if (op_type == IS_CONST) {
+#if ZEND_USE_ABS_CONST_ADDR
+ return ZEND_ADDR_CONST_ZVAL(op.zv);
+#else
+ return ZEND_ADDR_CONST_ZVAL(RT_CONSTANT(opline, op));
+#endif
+ } else {
+ ZEND_ASSERT(op_type & (IS_CV|IS_TMP_VAR|IS_VAR));
+ if (reg != ZREG_NONE) {
+ return ZEND_ADDR_REG(reg);
+ } else {
+ return ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
+ }
+ }
+}
+
+#define OP_ADDR(opline, type, op) \
+ _zend_jit_decode_op((opline)->type, (opline)->op, opline, ZREG_NONE)
+
+#define OP1_ADDR() \
+ OP_ADDR(opline, op1_type, op1)
+#define OP2_ADDR() \
+ OP_ADDR(opline, op2_type, op2)
+#define RES_ADDR() \
+ OP_ADDR(opline, op2_type, op2)
+#define OP1_DATA_ADDR() \
+ OP_ADDR(opline + 1, op1_type, op1)
+
+#define OP_REG_ADDR(opline, type, op, ssa_op) \
+ _zend_jit_decode_op((opline)->type, (opline)->op, opline, \
+ OP_REG((opline) - op_array->opcodes, ssa_op))
+
+#define OP1_REG_ADDR() \
+ OP_REG_ADDR(opline, op1_type, op1, op1_use)
+#define OP2_REG_ADDR() \
+ OP_REG_ADDR(opline, op2_type, op2, op2_use)
+#define RES_REG_ADDR() \
+ OP_REG_ADDR(opline, result_type, result, result_def)
+#define OP1_DATA_REG_ADDR() \
+ OP_REG_ADDR(opline + 1, op1_type, op1, op1_use)
+
+#define OP1_DEF_REG_ADDR() \
+ OP_REG_ADDR(opline, op1_type, op1, op1_def)
+#define OP2_DEF_REG_ADDR() \
+ OP_REG_ADDR(opline, op2_type, op2, op2_def)
+#define RES_USE_REG_ADDR() \
+ OP_REG_ADDR(opline, result_type, result, result_use)
+#define OP1_DATA_DEF_REG_ADDR() \
+ OP_REG_ADDR(opline + 1, op1_type, op1, op1_def)
+
+static zend_always_inline zend_bool zend_jit_same_addr(zend_jit_addr addr1, zend_jit_addr addr2)
+{
+ if (addr1 == addr2) {
+ return 1;
+ } else if (Z_MODE(addr1) == IS_REG && Z_MODE(addr2) == IS_REG) {
+ return Z_REG(addr1) == Z_REG(addr2);
+ }
+ return 0;
+}
+
+#endif /* ZEND_JIT_X86_H */
diff --git a/ext/opcache/opcache.stub.php b/ext/opcache/opcache.stub.php
new file mode 100644
index 0000000000..a60f237642
--- /dev/null
+++ b/ext/opcache/opcache.stub.php
@@ -0,0 +1,13 @@
+<?php
+
+function opcache_reset(): bool {}
+
+function opcache_get_status(bool $fetch_scripts = true): array|false {}
+
+function opcache_compile_file(string $file): bool {}
+
+function opcache_invalidate(string $script, bool $force = false): bool {}
+
+function opcache_get_configuration(): array|false {}
+
+function opcache_is_script_cached(string $script): bool {}
diff --git a/ext/opcache/opcache_arginfo.h b/ext/opcache/opcache_arginfo.h
new file mode 100644
index 0000000000..1b6ff24283
--- /dev/null
+++ b/ext/opcache/opcache_arginfo.h
@@ -0,0 +1,24 @@
+/* This is a generated file, edit the .stub.php file instead. */
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_reset, 0, 0, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_opcache_get_status, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE)
+ ZEND_ARG_TYPE_INFO(0, fetch_scripts, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_compile_file, 0, 1, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, file, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_invalidate, 0, 1, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, script, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, force, _IS_BOOL, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_opcache_get_configuration, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_is_script_cached, 0, 1, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, script, IS_STRING, 0)
+ZEND_END_ARG_INFO()
diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c
index dc02d038f5..8f900c1590 100644
--- a/ext/opcache/shared_alloc_mmap.c
+++ b/ext/opcache/shared_alloc_mmap.c
@@ -39,17 +39,10 @@
static int create_segments(size_t requested_size, zend_shared_segment ***shared_segments_p, int *shared_segments_count, char **error_in)
{
zend_shared_segment *shared_segment;
-
- *shared_segments_count = 1;
- *shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment) + sizeof(void *));
- if (!*shared_segments_p) {
- *error_in = "calloc";
- return ALLOC_FAILURE;
- }
- shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *));
- (*shared_segments_p)[0] = shared_segment;
-
+ void *p;
#ifdef MAP_HUGETLB
+ size_t huge_page_size = 2 * 1024 * 1024;
+
/* Try to allocate huge pages first to reduce dTLB misses.
* OSes has to be configured properly
* on Linux
@@ -60,21 +53,56 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
* sysctl vm.pmap.pg_ps_enabled entry
* (boot time config only, but enabled by default on most arches).
*/
- shared_segment->p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0);
- if (shared_segment->p != MAP_FAILED) {
- shared_segment->pos = 0;
- shared_segment->size = requested_size;
+ if (requested_size >= huge_page_size && requested_size % huge_page_size == 0) {
+# if defined(__x86_64__) && defined(MAP_32BIT)
+ /* to got HUGE PAGES in low 32-bit address we have to reserve address
+ space and then remap it using MAP_HUGETLB */
- return ALLOC_SUCCESS;
+ p = mmap(NULL, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_32BIT, -1, 0);
+ if (p != MAP_FAILED) {
+ munmap(p, requested_size);
+ p = (void*)(ZEND_MM_ALIGNED_SIZE_EX((ptrdiff_t)p, huge_page_size));
+ p = mmap(p, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_32BIT|MAP_HUGETLB|MAP_FIXED, -1, 0);
+ if (p != MAP_FAILED) {
+ goto success;
+ } else {
+ p = mmap(NULL, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_32BIT, -1, 0);
+ if (p != MAP_FAILED) {
+ goto success;
+ }
+ }
+ }
+# endif
+ p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0);
+ if (p != MAP_FAILED) {
+ goto success;
+ }
+ }
+#elif defined(PREFER_MAP_32BIT) && defined(__x86_64__) && defined(MAP_32BIT)
+ p = mmap(NULL, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS|MAP_32BIT, -1, 0);
+ if (p != MAP_FAILED) {
+ goto success;
}
#endif
- shared_segment->p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
- if (shared_segment->p == MAP_FAILED) {
+ p = mmap(0, requested_size, PROT_READ | PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+ if (p == MAP_FAILED) {
*error_in = "mmap";
return ALLOC_FAILURE;
}
+success: ZEND_ATTRIBUTE_UNUSED;
+ *shared_segments_count = 1;
+ *shared_segments_p = (zend_shared_segment **) calloc(1, sizeof(zend_shared_segment) + sizeof(void *));
+ if (!*shared_segments_p) {
+ munmap(p, requested_size);
+ *error_in = "calloc";
+ return ALLOC_FAILURE;
+ }
+ shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *));
+ (*shared_segments_p)[0] = shared_segment;
+
+ shared_segment->p = p;
shared_segment->pos = 0;
shared_segment->size = requested_size;
diff --git a/ext/opcache/shared_alloc_win32.c b/ext/opcache/shared_alloc_win32.c
index d2c31dd63b..856e33696a 100644
--- a/ext/opcache/shared_alloc_win32.c
+++ b/ext/opcache/shared_alloc_win32.c
@@ -197,7 +197,7 @@ static int zend_shared_alloc_reattach(size_t requested_size, char **error_in)
return ALLOC_FAILURE;
}
- mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, wanted_mapping_base);
+ mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE, 0, 0, 0, wanted_mapping_base);
if (mapping_base == NULL) {
err = GetLastError();
@@ -206,7 +206,16 @@ static int zend_shared_alloc_reattach(size_t requested_size, char **error_in)
return ALLOC_FAILURE;
}
return ALLOC_FAIL_MAPPING;
+ } else {
+ DWORD old;
+
+ if (!VirtualProtect(mapping_base, requested_size, PAGE_READWRITE, &old)) {
+ err = GetLastError();
+ zend_win_error_message(ACCEL_LOG_FATAL, "VirtualProtect() failed", err);
+ return ALLOC_FAIL_MAPPING;
+ }
}
+
smm_shared_globals = (zend_smm_shared_globals *) mapping_base;
return SUCCESSFULLY_REATTACHED;
@@ -237,7 +246,7 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
can be called before the child process is killed. In this case, the map will fail
and we have to sleep some time (until the child releases the mapping object) and retry.*/
do {
- memfile = OpenFileMapping(FILE_MAP_WRITE, 0, create_name_with_username(ACCEL_FILEMAP_NAME));
+ memfile = OpenFileMapping(FILE_MAP_READ|FILE_MAP_WRITE|FILE_MAP_EXECUTE, 0, create_name_with_username(ACCEL_FILEMAP_NAME));
if (memfile == NULL) {
err = GetLastError();
break;
@@ -281,7 +290,7 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
shared_segment = (zend_shared_segment *)((char *)(*shared_segments_p) + sizeof(void *));
(*shared_segments_p)[0] = shared_segment;
- memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, size_high, size_low,
+ memfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE | SEC_COMMIT, size_high, size_low,
create_name_with_username(ACCEL_FILEMAP_NAME));
if (memfile == NULL) {
err = GetLastError();
@@ -311,7 +320,7 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
}
do {
- shared_segment->p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS, 0, 0, 0, *wanted_mapping_base);
+ shared_segment->p = mapping_base = MapViewOfFileEx(memfile, FILE_MAP_ALL_ACCESS|FILE_MAP_EXECUTE, 0, 0, 0, *wanted_mapping_base);
if (*wanted_mapping_base == NULL) { /* Auto address (NULL) is the last option on the array */
break;
}
@@ -325,9 +334,18 @@ static int create_segments(size_t requested_size, zend_shared_segment ***shared_
*error_in = "MapViewOfFile";
return ALLOC_FAILURE;
} else {
- char *mmap_base_file = get_mmap_base_file();
+ char *mmap_base_file;
void *execute_ex_base = (void *)execute_ex;
- FILE *fp = fopen(mmap_base_file, "w");
+ FILE *fp;
+ DWORD old;
+
+ if (!VirtualProtect(mapping_base, requested_size, PAGE_READWRITE, &old)) {
+ err = GetLastError();
+ zend_win_error_message(ACCEL_LOG_FATAL, "VirtualProtect() failed", err);
+ return ALLOC_FAILURE;
+ }
+ mmap_base_file = get_mmap_base_file();
+ fp = fopen(mmap_base_file, "w");
if (!fp) {
err = GetLastError();
zend_shared_alloc_unlock_win32();
diff --git a/ext/opcache/tests/assign_obj_op_of_fetch_dim.phpt b/ext/opcache/tests/assign_obj_op_of_fetch_dim.phpt
index c89d0bea62..2c07051778 100644
--- a/ext/opcache/tests/assign_obj_op_of_fetch_dim.phpt
+++ b/ext/opcache/tests/assign_obj_op_of_fetch_dim.phpt
@@ -8,13 +8,13 @@ function test() {
$ary[0]->y += 2;
var_dump(is_object($ary[0]));
}
-test();
+try {
+ test();
+} catch (Error $e) {
+ echo $e->getMessage(), "\n";
+}
?>
--EXPECTF--
Notice: Undefined offset: 0 in %s on line %d
-
-Warning: Creating default object from empty value in %s on line %d
-
-Notice: Undefined property: stdClass::$y in %s on line %d
-bool(true)
+Attempt to assign property 'y' of non-object
diff --git a/ext/opcache/tests/blacklist.inc b/ext/opcache/tests/blacklist.inc
index a9db751419..65adb91ced 100644
--- a/ext/opcache/tests/blacklist.inc
+++ b/ext/opcache/tests/blacklist.inc
@@ -1,3 +1,3 @@
<?php
- echo "ok\n";
+ echo "ok\n";
?>
diff --git a/ext/opcache/tests/block_pass_001.phpt b/ext/opcache/tests/block_pass_001.phpt
index c024b81ce8..7fab78bbe8 100644
--- a/ext/opcache/tests/block_pass_001.phpt
+++ b/ext/opcache/tests/block_pass_001.phpt
@@ -9,4 +9,4 @@ Block pass: Bugs in BOOL/QM_ASSIGN elision
(bool) new stdClass;
?>
--EXPECTF--
-Notice: Undefined variable: x in %s on line %d
+Warning: Undefined variable: x in %s on line %d
diff --git a/ext/opcache/tests/bool_not_cv.phpt b/ext/opcache/tests/bool_not_cv.phpt
index ed3cf83514..cc28edcc01 100644
--- a/ext/opcache/tests/bool_not_cv.phpt
+++ b/ext/opcache/tests/bool_not_cv.phpt
@@ -26,9 +26,9 @@ undef_bool_cast();
--EXPECTF--
In undef_negation
-Notice: Undefined variable: v in %s on line 4
+Warning: Undefined variable: v in %s on line 4
true
In undef_bool_cast
-Notice: Undefined variable: v in %s on line 10
+Warning: Undefined variable: v in %s on line 10
false
diff --git a/ext/opcache/tests/bug64353.phpt b/ext/opcache/tests/bug64353.phpt
index 42cb45c915..bfb332e26e 100644
--- a/ext/opcache/tests/bug64353.phpt
+++ b/ext/opcache/tests/bug64353.phpt
@@ -9,16 +9,16 @@ opcache.enable_cli=1
--FILE--
<?php
class BugLoader extends php_user_filter {
- public function filter($in, $out, &$consumed, $closing) {
- if (!class_exists("Test")) {
- eval("class Test extends ArrayObject {}");
- }
- while ($bucket = stream_bucket_make_writeable($in)) {
- $consumed += $bucket->datalen;
- stream_bucket_append($out, $bucket);
- }
- return PSFS_PASS_ON;
- }
+ public function filter($in, $out, &$consumed, $closing) {
+ if (!class_exists("Test")) {
+ eval("class Test extends ArrayObject {}");
+ }
+ while ($bucket = stream_bucket_make_writeable($in)) {
+ $consumed += $bucket->datalen;
+ stream_bucket_append($out, $bucket);
+ }
+ return PSFS_PASS_ON;
+ }
}
stream_filter_register('bug.test', 'BugLoader');
diff --git a/ext/opcache/tests/bug65665.phpt b/ext/opcache/tests/bug65665.phpt
index ac5c18dd83..bcdd0e6da1 100644
--- a/ext/opcache/tests/bug65665.phpt
+++ b/ext/opcache/tests/bug65665.phpt
@@ -8,108 +8,108 @@ opcache.enable_cli=1
--FILE--
<?php
function foo() {
- try
- {
- switch (1)
- {
- case 0:
- try
- {
+ try
+ {
+ switch (1)
+ {
+ case 0:
+ try
+ {
- }
- catch (Exception $e)
- {
+ }
+ catch (Exception $e)
+ {
- }
+ }
- break;
+ break;
- case 1:
- try
- {
- throw new Exception('aaa');
- }
- catch (Exception $e)
- {
- echo "correct\n";
- }
+ case 1:
+ try
+ {
+ throw new Exception('aaa');
+ }
+ catch (Exception $e)
+ {
+ echo "correct\n";
+ }
- break;
- }
- }
- catch (Exception $e)
- {
- echo "wrong\n";
- }
- return;
+ break;
+ }
+ }
+ catch (Exception $e)
+ {
+ echo "wrong\n";
+ }
+ return;
}
function foo1() {
- try
- {
- switch (1)
- {
- case 0:
- try
- {
+ try
+ {
+ switch (1)
+ {
+ case 0:
+ try
+ {
- }
- catch (Exception $e)
- {
+ }
+ catch (Exception $e)
+ {
dummy:
- echo "ect\n";
- }
+ echo "ect\n";
+ }
- break;
+ break;
- case 1:
- try
- {
- throw new Exception('aaa');
- }
- catch (Exception $e)
- {
- echo "corr";
- goto dummy;
- }
- break;
- }
- }
- catch (Exception $e)
- {
- echo "wrong\n";
- }
- return;
+ case 1:
+ try
+ {
+ throw new Exception('aaa');
+ }
+ catch (Exception $e)
+ {
+ echo "corr";
+ goto dummy;
+ }
+ break;
+ }
+ }
+ catch (Exception $e)
+ {
+ echo "wrong\n";
+ }
+ return;
}
function foo2() {
- try
- {
- switch (1)
- {
- case 0:
- try
- {
+ try
+ {
+ switch (1)
+ {
+ case 0:
+ try
+ {
dummy:
- throw new Exception('aaa');
- }
- catch (Exception $e)
- {
- echo "correct\n";
- }
+ throw new Exception('aaa');
+ }
+ catch (Exception $e)
+ {
+ echo "correct\n";
+ }
- break;
+ break;
- case 1:
- goto dummy;
- break;
- }
- }
- catch (Exception $e)
- {
- echo "wrong\n";
- }
- return;
+ case 1:
+ goto dummy;
+ break;
+ }
+ }
+ catch (Exception $e)
+ {
+ echo "wrong\n";
+ }
+ return;
}
foo();foo1();foo2();
--EXPECT--
diff --git a/ext/opcache/tests/bug66176.phpt b/ext/opcache/tests/bug66176.phpt
index a91024a616..a7c53c1690 100644
--- a/ext/opcache/tests/bug66176.phpt
+++ b/ext/opcache/tests/bug66176.phpt
@@ -10,8 +10,8 @@ opcache.file_update_protection=0
--FILE--
<?php
function foo($v) {
- global $a;
- return $a[$v];
+ global $a;
+ return $a[$v];
}
$a = array(PHP_VERSION => 1);
var_dump(foo(PHP_VERSION));
diff --git a/ext/opcache/tests/bug66251.phpt b/ext/opcache/tests/bug66251.phpt
index daa5a89bb2..42c6e2f606 100644
--- a/ext/opcache/tests/bug66251.phpt
+++ b/ext/opcache/tests/bug66251.phpt
@@ -5,7 +5,7 @@ opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
--SKIPIF--
-<?php if (!extension_loaded('Zend OPcache') || php_sapi_name() != "cli") die("skip CLI only"); ?>
+<?php if (!extension_loaded('Zend OPcache')) die("skip Zend OPcache extension not loaded"); ?>
--FILE--
<?php
printf ("A=%s\n", getA());
@@ -13,5 +13,8 @@ const A="hello";
function getA() {return A;}
?>
--EXPECTF--
-Warning: Use of undefined constant A - assumed 'A' (this will throw an Error in a future version of PHP) in %sbug66251.php on line 4
-A=A
+Fatal error: Uncaught Error: Undefined constant 'A' in %s:%d
+Stack trace:
+#0 %s(%d): getA()
+#1 {main}
+ thrown in %s on line %d
diff --git a/ext/opcache/tests/bug66334.phpt b/ext/opcache/tests/bug66334.phpt
index b2c6d7b92c..33e3847e34 100644
--- a/ext/opcache/tests/bug66334.phpt
+++ b/ext/opcache/tests/bug66334.phpt
@@ -11,9 +11,9 @@ enable_dl=0
--FILE--
<?php
if (extension_loaded("unknown_extension")) {
- var_dump(1);
+ var_dump(1);
} else {
- var_dump(2);
+ var_dump(2);
}
--EXPECT--
int(2)
diff --git a/ext/opcache/tests/bug66338.phpt b/ext/opcache/tests/bug66338.phpt
index 5cd9693793..1473481561 100644
--- a/ext/opcache/tests/bug66338.phpt
+++ b/ext/opcache/tests/bug66338.phpt
@@ -3,7 +3,7 @@ Bug #66338 (Optimization binding of class constants is not safely opcacheable)
--INI--
opcache.enable=0
--SKIPIF--
-<?php if (!extension_loaded('Zend OPcache') || php_sapi_name() != "cli") die("skip CLI only"); ?>
+<?php if (!extension_loaded('Zend OPcache')) die("skip Zend OPcache extension not loaded"); ?>
--CONFLICTS--
server
--FILE--
@@ -12,20 +12,20 @@ $root = str_replace('.php', "", __FILE__);
$base = basename( $root );
file_put_contents( "$root-Officials.inc", '<?php
- class Officials { static function getLeader() { return LocalTerms::GOV_LEADER; } }
- ' );
+ class Officials { static function getLeader() { return LocalTerms::GOV_LEADER; } }
+ ' );
file_put_contents( "$root-clientUS.php", '<?php
- class LocalTerms { const GOV_LEADER = "Barack Hussein Obama II"; }
- require \''.$root.'-Officials.inc\';
- printf( "The President of the USA is %s\n", Officials::getLeader() );
- ' );
+ class LocalTerms { const GOV_LEADER = "Barack Hussein Obama II"; }
+ require \''.$root.'-Officials.inc\';
+ printf( "The President of the USA is %s\n", Officials::getLeader() );
+ ' );
file_put_contents( "$root-clientUK.php", '<?php
- class LocalTerms { const GOV_LEADER = "David William Donald Cameron"; }
- require \''.$root.'-Officials.inc\';
- printf( "The Prime Minister of the UK is %s\n", Officials::getLeader() );
- ' );
+ class LocalTerms { const GOV_LEADER = "David William Donald Cameron"; }
+ require \''.$root.'-Officials.inc\';
+ printf( "The Prime Minister of the UK is %s\n", Officials::getLeader() );
+ ' );
include "php_cli_server.inc";
$uri = sprintf("http://%s/%s", PHP_CLI_SERVER_ADDRESS, basename(__FILE__));
diff --git a/ext/opcache/tests/bug66440.phpt b/ext/opcache/tests/bug66440.phpt
index b546e32b3c..539b0ce7aa 100644
--- a/ext/opcache/tests/bug66440.phpt
+++ b/ext/opcache/tests/bug66440.phpt
@@ -10,7 +10,7 @@ opcache.file_update_protection=0
--FILE--
<?php
if(constant('PHP_BINARY')) {
- echo "OK\n";
+ echo "OK\n";
}
--EXPECT--
OK
diff --git a/ext/opcache/tests/bug66474.phpt b/ext/opcache/tests/bug66474.phpt
index 3bd038c0de..10d54a7fa5 100644
--- a/ext/opcache/tests/bug66474.phpt
+++ b/ext/opcache/tests/bug66474.phpt
@@ -10,7 +10,7 @@ opcache.file_update_protection=0
--FILE--
<?php
function foo() {
- $speed = 'slow' || 'fast';
+ $speed = 'slow' || 'fast';
}
foo();
echo "ok\n";
diff --git a/ext/opcache/tests/bug68252.phpt b/ext/opcache/tests/bug68252.phpt
deleted file mode 100644
index bc2e5a0fb6..0000000000
--- a/ext/opcache/tests/bug68252.phpt
+++ /dev/null
@@ -1,21 +0,0 @@
---TEST--
-Bug #68252 (segfault in Zend/zend_hash.c in function _zend_hash_del_el)
---INI--
-opcache.enable=1
-opcache.enable_cli=1
-opcache.fast_shutdown=1
---SKIPIF--
-<?php require_once('skipif.inc'); ?>
---FILE--
-<?php
-/* run this test script with valgrind */
-function a() {
- echo "okey";
-}
-
-create_function('', 'var_dump("22");');
-
-a();
---EXPECTF--
-Deprecated: Function create_function() is deprecated in %s on line %d
-okey
diff --git a/ext/opcache/tests/bug68644.phpt b/ext/opcache/tests/bug68644.phpt
deleted file mode 100644
index 1a967facaf..0000000000
--- a/ext/opcache/tests/bug68644.phpt
+++ /dev/null
@@ -1,17 +0,0 @@
---TEST--
-Bug #68644 strlen incorrect : mbstring + func_overload=2 + UTF-8 + Opcache
---INI--
-opcache.enable=1
-opcache.enable_cli=1
-mbstring.func_overload=2
---SKIPIF--
-<?php if (!extension_loaded('Zend OPcache') || !extension_loaded("mbstring")) die("skip"); ?>
---FILE--
-<?php
-var_dump(strlen("中国, 北京"));
-var_dump(mb_strlen("中国, 北京"));
-?>
---EXPECT--
-Deprecated: The mbstring.func_overload directive is deprecated in Unknown on line 0
-int(6)
-int(6)
diff --git a/ext/opcache/tests/bug69038.phpt b/ext/opcache/tests/bug69038.phpt
index 1670a9eca6..09b9af4077 100644
--- a/ext/opcache/tests/bug69038.phpt
+++ b/ext/opcache/tests/bug69038.phpt
@@ -10,50 +10,50 @@ opcache.optimization_level=-1
<?php
function a($a = "bad") {
- switch (PHP_OS) {
- case "LALALALA" : return "LALALAL";
- case PHP_OS: return "okey";
- default: break;
- }
+ switch (PHP_OS) {
+ case "LALALALA" : return "LALALAL";
+ case PHP_OS: return "okey";
+ default: break;
+ }
- return $a;
+ return $a;
}
var_dump(a());
function b($b = "bad") {
- switch (PHP_OS) {
- case "LALALAL": return "bad";
- case PHP_OS:
- switch (PHP_OS) {
- case "FOO": break;
- case PHP_OS: return "okey";
- default :
- break;
- }
- break;
- default:
- break;
- }
- return $b;
+ switch (PHP_OS) {
+ case "LALALAL": return "bad";
+ case PHP_OS:
+ switch (PHP_OS) {
+ case "FOO": break;
+ case PHP_OS: return "okey";
+ default :
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return $b;
}
var_dump(b());
function c($b = "bad") {
- switch (extension_loaded("standard")) {
- case 0 : return "LALALAL";
- case 1 : return "okey";
- default : return "bad";
- }
+ switch (extension_loaded("standard")) {
+ case 0 : return "LALALAL";
+ case 1 : return "okey";
+ default : return "bad";
+ }
}
var_dump(c());
function d() {
- switch (PHP_OS) {
- default: return "bad";
- case PHP_OS: return "okey";
- }
+ switch (PHP_OS) {
+ default: return "bad";
+ case PHP_OS: return "okey";
+ }
}
var_dump(d());
diff --git a/ext/opcache/tests/bug69159.phpt b/ext/opcache/tests/bug69159.phpt
index d8b953a1aa..158f242b3f 100644
--- a/ext/opcache/tests/bug69159.phpt
+++ b/ext/opcache/tests/bug69159.phpt
@@ -12,7 +12,7 @@ $x1 = "okey";
myFunction(${"x$i"});
function myFunction($x) {
- var_dump($x);
+ var_dump($x);
}
?>
diff --git a/ext/opcache/tests/bug70207.phpt b/ext/opcache/tests/bug70207.phpt
index c684ee6d33..a73b7a6916 100644
--- a/ext/opcache/tests/bug70207.phpt
+++ b/ext/opcache/tests/bug70207.phpt
@@ -10,11 +10,13 @@ opcache.file_update_protection=0
--FILE--
<?php
function bar() {
- return "bar";
+ return "bar";
}
function foo() {
try { return bar(); }
- finally { @fclose(null); }
+ finally {
+ @fopen("non-existent", 'r');
+ }
}
var_dump(foo());
diff --git a/ext/opcache/tests/bug71843.phpt b/ext/opcache/tests/bug71843.phpt
index 924fb873fe..0a193425dd 100644
--- a/ext/opcache/tests/bug71843.phpt
+++ b/ext/opcache/tests/bug71843.phpt
@@ -8,18 +8,15 @@ opcache.optimization_level=0xFFFFBFFF
<?php if (!extension_loaded('Zend OPcache')) die("skip"); ?>
--FILE--
<?php
+define('E', 'E');
+define('R', 'R');
+define('See', 'See');
0 & ~E & ~R;
6 && ~See
?>
okey
--EXPECTF--
-Warning: Use of undefined constant E - assumed 'E' (this will throw an Error in a future version of PHP) in %sbug71843.php on line %d
-
Warning: A non-numeric value encountered in %s on line %d
-Warning: Use of undefined constant R - assumed 'R' (this will throw an Error in a future version of PHP) in %sbug71843.php on line %d
-
Warning: A non-numeric value encountered in %s on line %d
-
-Warning: Use of undefined constant See - assumed 'See' (this will throw an Error in a future version of PHP) in %sbug71843.php on line %d
okey
diff --git a/ext/opcache/tests/bug73402.phpt b/ext/opcache/tests/bug73402.phpt
index f325b798e5..d245d58969 100644
--- a/ext/opcache/tests/bug73402.phpt
+++ b/ext/opcache/tests/bug73402.phpt
@@ -8,19 +8,19 @@ opcache.enable_cli=1
--FILE--
<?php
class Logger {
- public function info($msg) {
- echo $msg;
- }
+ public function info($msg) {
+ echo $msg;
+ }
}
class B
{
- const LOG_LEVEL = 'Info';
- public function test()
- {
- $logger = new \Logger();
- $logger->{self::LOG_LEVEL}('test');
- }
+ const LOG_LEVEL = 'Info';
+ public function test()
+ {
+ $logger = new \Logger();
+ $logger->{self::LOG_LEVEL}('test');
+ }
}
$b = new B;
diff --git a/ext/opcache/tests/bug73583.phpt b/ext/opcache/tests/bug73583.phpt
index e947b451c9..f533e9caf5 100644
--- a/ext/opcache/tests/bug73583.phpt
+++ b/ext/opcache/tests/bug73583.phpt
@@ -10,9 +10,9 @@ opcache.file_update_protection=0
--FILE--
<?php
if (true) {
- class A { }
- function A() { }
- function A() { }
+ class A { }
+ function A() { }
+ function A() { }
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/bug73668.phpt b/ext/opcache/tests/bug73668.phpt
index 379ba4a5ac..b2a0508aa5 100644
--- a/ext/opcache/tests/bug73668.phpt
+++ b/ext/opcache/tests/bug73668.phpt
@@ -7,4 +7,4 @@ Bug #73668: "SIGFPE Arithmetic exception" in opcache when divide by minus 1
$a/-1;
?>
--EXPECTF--
-Notice: Undefined variable: a in %s on line %d
+Warning: Undefined variable: a in %s on line %d
diff --git a/ext/opcache/tests/bug73746.phpt b/ext/opcache/tests/bug73746.phpt
index 4f115575cf..c95aed8076 100644
--- a/ext/opcache/tests/bug73746.phpt
+++ b/ext/opcache/tests/bug73746.phpt
@@ -8,19 +8,19 @@ namespace Core\Bundle\Service\Property\Room\Rooms;
class CountryMapping
{
- const CZ = 'CZ';
- const EN = 'EN';
+ const CZ = 'CZ';
+ const EN = 'EN';
- public function get(string $countryIsoCode = null) : string // Works correctly if return type is removed
- {
- switch (strtoupper($countryIsoCode)) {
- case 'CZ':
- case 'SK':
- return self::CZ; // Works correctly if changed to CountryMapping::CZ
- default:
- return self::EN; // Works correctly if changed to CountryMapping::EN
- }
- }
+ public function get(string $countryIsoCode = null) : string // Works correctly if return type is removed
+ {
+ switch (strtoupper($countryIsoCode)) {
+ case 'CZ':
+ case 'SK':
+ return self::CZ; // Works correctly if changed to CountryMapping::CZ
+ default:
+ return self::EN; // Works correctly if changed to CountryMapping::EN
+ }
+ }
}
$mapping = new CountryMapping();
diff --git a/ext/opcache/tests/bug73789.phpt b/ext/opcache/tests/bug73789.phpt
index d5efeb403d..5d5cb92f20 100644
--- a/ext/opcache/tests/bug73789.phpt
+++ b/ext/opcache/tests/bug73789.phpt
@@ -7,26 +7,26 @@ Bug #73789 (Strange behavior of class constants in switch/case block)
<?php
class Lexer
{
- const T_NONE = 1;
- const T_STRING = 2;
- const T_DOT = 8;
- public function getType($value): int
- {
- $type = self::T_NONE;
- switch (true) {
- case ctype_alpha($value[0]):
- $name = 'Lexer::T_' . strtoupper($value);
- $type = constant($name);
- if ($type > 100) {
- return $type;
- }
- return self::T_STRING;
- case $value === '.':
- return self::T_DOT;
- default:
- }
- return $type;
- }
+ const T_NONE = 1;
+ const T_STRING = 2;
+ const T_DOT = 8;
+ public function getType($value): int
+ {
+ $type = self::T_NONE;
+ switch (true) {
+ case ctype_alpha($value[0]):
+ $name = 'Lexer::T_' . strtoupper($value);
+ $type = constant($name);
+ if ($type > 100) {
+ return $type;
+ }
+ return self::T_STRING;
+ case $value === '.':
+ return self::T_DOT;
+ default:
+ }
+ return $type;
+ }
}
var_dump((new Lexer())->getType("dot"));
?>
diff --git a/ext/opcache/tests/bug74019.phpt b/ext/opcache/tests/bug74019.phpt
index 210e223c82..0392963a8b 100644
--- a/ext/opcache/tests/bug74019.phpt
+++ b/ext/opcache/tests/bug74019.phpt
@@ -9,12 +9,12 @@ opcache.enable_cli=1
<?php
class A {
- public function seg() {
- list($a, $b) = A::CONSTS;
- var_dump($a, $b);
- return;
- }
- const CONSTS = [1, 2];
+ public function seg() {
+ list($a, $b) = A::CONSTS;
+ var_dump($a, $b);
+ return;
+ }
+ const CONSTS = [1, 2];
}
$a = new A;
diff --git a/ext/opcache/tests/bug74152.phpt b/ext/opcache/tests/bug74152.phpt
index f51c26b621..b991365927 100644
--- a/ext/opcache/tests/bug74152.phpt
+++ b/ext/opcache/tests/bug74152.phpt
@@ -16,11 +16,11 @@ $bar = null;
switch ($foo) {
default:
case 'foo':
- if ($bar) {
- echo 'true';
- } else {
- echo 'false';
- }
+ if ($bar) {
+ echo 'true';
+ } else {
+ echo 'false';
+ }
}
?>
--EXPECT--
diff --git a/ext/opcache/tests/bug74456.phpt b/ext/opcache/tests/bug74456.phpt
index 9c9a286e2f..10f9b04058 100644
--- a/ext/opcache/tests/bug74456.phpt
+++ b/ext/opcache/tests/bug74456.phpt
@@ -11,7 +11,7 @@ opcache.optimization_level=-1
function small_numbers() {
- return [0,1,2];
+ return [0,1,2];
}
list ($zero, $one, $two) = small_numbers();
diff --git a/ext/opcache/tests/bug74596.phpt b/ext/opcache/tests/bug74596.phpt
index ed1c1b4504..8a1dc17189 100644
--- a/ext/opcache/tests/bug74596.phpt
+++ b/ext/opcache/tests/bug74596.phpt
@@ -15,14 +15,14 @@ opcache.revalidate_path=1
file_put_contents(__DIR__ . "/bug74596_1.php", <<<CODE
<?php
class A {
- public function __construct() {
- \$a = true;
- if (\$a) {
- echo 1 + 2;
- } else {
- echo 2 + 3;
- }
- }
+ public function __construct() {
+ \$a = true;
+ if (\$a) {
+ echo 1 + 2;
+ } else {
+ echo 2 + 3;
+ }
+ }
}
?>
CODE
@@ -32,14 +32,14 @@ file_put_contents(__DIR__ . "/bug74596_2.php", "ok\n");
class ufilter extends php_user_filter
{
- function filter($in, $out, &$consumed, $closing)
- {
- include_once __DIR__ . "/bug74596_1.php";
- while ($bucket = stream_bucket_make_writeable($in)) {
- stream_bucket_append($out, $bucket);
- }
- return PSFS_PASS_ON;
- }
+ function filter($in, $out, &$consumed, $closing)
+ {
+ include_once __DIR__ . "/bug74596_1.php";
+ while ($bucket = stream_bucket_make_writeable($in)) {
+ stream_bucket_append($out, $bucket);
+ }
+ return PSFS_PASS_ON;
+ }
}
stream_filter_register("ufilter", "ufilter");
diff --git a/ext/opcache/tests/bug74980.phpt b/ext/opcache/tests/bug74980.phpt
index e82e234bdd..df77206d7b 100644
--- a/ext/opcache/tests/bug74980.phpt
+++ b/ext/opcache/tests/bug74980.phpt
@@ -11,16 +11,16 @@ opcache.enable_cli=1
class A
{
- static function foo()
- {
- while ($undef) {
- $arr[][] = NULL;
- }
+ static function foo()
+ {
+ while ($undef) {
+ $arr[][] = NULL;
+ }
- foreach ($arr as $a) {
- bar($a + []);
- }
- }
+ foreach ($arr as $a) {
+ bar($a + []);
+ }
+ }
}
diff --git a/ext/opcache/tests/bug75230.phpt b/ext/opcache/tests/bug75230.phpt
index 13100b3679..ce67bb06b9 100644
--- a/ext/opcache/tests/bug75230.phpt
+++ b/ext/opcache/tests/bug75230.phpt
@@ -9,8 +9,8 @@ opcache.optimization_level=-1
--FILE--
<?php
function f() {
- $retval = false;
- if ($retval) { }
+ $retval = false;
+ if ($retval) { }
}
f();
exit("OK");
diff --git a/ext/opcache/tests/bug75357.phpt b/ext/opcache/tests/bug75357.phpt
index 359f6160c2..99537ed097 100644
--- a/ext/opcache/tests/bug75357.phpt
+++ b/ext/opcache/tests/bug75357.phpt
@@ -10,23 +10,23 @@ opcache.optimization_level=-1
<?php
function wp_slash( $value ) {
- if ( is_array( $value ) ) {
- foreach ( $value as $k => $v ) {
- if ( is_array( $v ) ) {
- $value[$k] = wp_slash( $v );
- } else {
- $value[$k] = addslashes( $v );
- }
- }
- } else {
- $value = addslashes( $value );
- }
+ if ( is_array( $value ) ) {
+ foreach ( $value as $k => $v ) {
+ if ( is_array( $v ) ) {
+ $value[$k] = wp_slash( $v );
+ } else {
+ $value[$k] = addslashes( $v );
+ }
+ }
+ } else {
+ $value = addslashes( $value );
+ }
- return $value;
+ return $value;
}
function addslashes_gpc($gpc) {
- return wp_slash($gpc);
+ return wp_slash($gpc);
}
var_dump(addslashes_gpc(array(array("test"))));
diff --git a/ext/opcache/tests/bug75370.phpt b/ext/opcache/tests/bug75370.phpt
index d576f592d4..5cc344e3f6 100644
--- a/ext/opcache/tests/bug75370.phpt
+++ b/ext/opcache/tests/bug75370.phpt
@@ -10,9 +10,9 @@ opcache.optimization_level=-1
<?php
function test()
{
- $success = true;
- $success = $success AND true;
- return $success;
+ $success = true;
+ $success = $success AND true;
+ return $success;
}
var_dump(test());
diff --git a/ext/opcache/tests/bug75556.phpt b/ext/opcache/tests/bug75556.phpt
index 1b2511c580..c1faa5e15a 100644
--- a/ext/opcache/tests/bug75556.phpt
+++ b/ext/opcache/tests/bug75556.phpt
@@ -10,14 +10,14 @@ opcache.optimization_level=-1
<?php
function createFromFormat($format, $date, ?\DateTimeZone $tz = null): ?\DateTimeInterface
{
- if ($tz !== null
- || ($tz instanceof \DateTimeZone && !in_array($tz->getName(), ['UTC', 'Z'], true))
- ) {
- $msg = 'Date objects must have UTC as their timezone';
- throw new \UnexpectedValueException($msg);
- }
+ if ($tz !== null
+ || ($tz instanceof \DateTimeZone && !in_array($tz->getName(), ['UTC', 'Z'], true))
+ ) {
+ $msg = 'Date objects must have UTC as their timezone';
+ throw new \UnexpectedValueException($msg);
+ }
- return null;
+ return null;
}
var_dump(createFromFormat('m/d/Y', '12/07/2017', null));
diff --git a/ext/opcache/tests/bug75687.phpt b/ext/opcache/tests/bug75687.phpt
index 67cf8288a9..1d9c55f96c 100644
--- a/ext/opcache/tests/bug75687.phpt
+++ b/ext/opcache/tests/bug75687.phpt
@@ -11,9 +11,9 @@ opcache.optimization_level=-1
function x($y)
{
- if (is_array($y)) {
- $z = is_array($y) ? array() : array($y);
- }
+ if (is_array($y)) {
+ $z = is_array($y) ? array() : array($y);
+ }
}
?>
okey
diff --git a/ext/opcache/tests/bug75729.phpt b/ext/opcache/tests/bug75729.phpt
deleted file mode 100644
index 52b004c75a..0000000000
--- a/ext/opcache/tests/bug75729.phpt
+++ /dev/null
@@ -1,21 +0,0 @@
---TEST--
-Bug #75729: opcache segfault when installing Bitrix
---SKIPIF--
-<?php require_once('skipif.inc'); ?>
-<?php if (!extension_loaded('mbstring')) die('skip mbstring not loaded'); ?>
---INI--
-opcache.enable_cli=1
-mbstring.func_overload=2
---FILE--
-<?php
-
-var_dump(strpos("foo", "o"));
-var_dump(substr("foo", 1));
-var_dump(substr("foo", 1, 1));
-
-?>
---EXPECT--
-Deprecated: The mbstring.func_overload directive is deprecated in Unknown on line 0
-int(1)
-string(2) "oo"
-string(1) "o"
diff --git a/ext/opcache/tests/bug75893.phpt b/ext/opcache/tests/bug75893.phpt
deleted file mode 100644
index 9ca713b121..0000000000
--- a/ext/opcache/tests/bug75893.phpt
+++ /dev/null
@@ -1,24 +0,0 @@
---TEST--
-Bug #75893: file_get_contents $http_response_header variable bugged with opcache
---INI--
-opcache.enable_cli=1
-track_errors=1
---SKIPIF--
-<?php require_once('skipif.inc'); ?>
---FILE--
-<?php
-
-function test() {
- echo $undef;
- $foo = $php_errormsg;
- var_dump($foo[0]);
-}
-
-test();
-
-?>
---EXPECTF--
-Deprecated: Directive 'track_errors' is deprecated in Unknown on line 0
-
-Notice: Undefined variable: undef in %s on line %d
-string(1) "U"
diff --git a/ext/opcache/tests/bug75938.phpt b/ext/opcache/tests/bug75938.phpt
index cfe6a65503..7fba940e97 100644
--- a/ext/opcache/tests/bug75938.phpt
+++ b/ext/opcache/tests/bug75938.phpt
@@ -5,11 +5,11 @@ Bug #75938: Modulus value not stored in variable
--FILE--
<?php
function borken($columns) {
- $columns = (int) $columns;
- if ($columns < 1) return 0;
- $count = count([1,2,3,4,5]);
- var_dump($mod = ($count % $columns));
- var_dump($mod);
+ $columns = (int) $columns;
+ if ($columns < 1) return 0;
+ $count = count([1,2,3,4,5]);
+ var_dump($mod = ($count % $columns));
+ var_dump($mod);
}
borken(2);
?>
diff --git a/ext/opcache/tests/bug76074.phpt b/ext/opcache/tests/bug76074.phpt
index d12ebb26fa..94c79beff6 100644
--- a/ext/opcache/tests/bug76074.phpt
+++ b/ext/opcache/tests/bug76074.phpt
@@ -6,8 +6,8 @@ Bug #76074 (opcache corrupts variable in for-loop)
<?php
function test(int $nr) {
- for ($i = $nr; $i <= $nr + 1; $i++)
- var_dump($i);
+ for ($i = $nr; $i <= $nr + 1; $i++)
+ var_dump($i);
}
test(1);
diff --git a/ext/opcache/tests/bug76094.phpt b/ext/opcache/tests/bug76094.phpt
index 4f5e037ead..35f8d321de 100644
--- a/ext/opcache/tests/bug76094.phpt
+++ b/ext/opcache/tests/bug76094.phpt
@@ -11,13 +11,13 @@ opcache.optimization_level=-1
function MetaType($t)
{
- switch (strtoupper($t)) {
- case PHP_INT_MAX :
- return 1;
- case 0:
- default:
- return 0;
- }
+ switch (strtoupper($t)) {
+ case PHP_INT_MAX :
+ return 1;
+ case 0:
+ default:
+ return 0;
+ }
}
var_dump(MetaType("aa"));
diff --git a/ext/opcache/tests/bug76446.phpt b/ext/opcache/tests/bug76446.phpt
index dfb676f4ba..a2b02de032 100644
--- a/ext/opcache/tests/bug76446.phpt
+++ b/ext/opcache/tests/bug76446.phpt
@@ -10,13 +10,13 @@ opcache.optimization_level=-1
<?php
function test()
{
- $openmenu = '';
- $openstr2 = "&amp;openmenu={$openmenu}{$addlang}\"";
- return 0;
+ $openmenu = '';
+ $openstr2 = "&amp;openmenu={$openmenu}{$addlang}\"";
+ return 0;
}
var_dump(test());
?>
--EXPECTF--
-Notice: Undefined variable: addlang in %sbug76446.php on line %d
+Warning: Undefined variable: addlang in %s on line %d
int(0)
diff --git a/ext/opcache/tests/bug76463.phpt b/ext/opcache/tests/bug76463.phpt
index 0fa9be990c..e3dacb691c 100644
--- a/ext/opcache/tests/bug76463.phpt
+++ b/ext/opcache/tests/bug76463.phpt
@@ -10,7 +10,7 @@ opcache.optimization_level=-1
<?php
function test() {
- $old_data = isset($old_data) ? (array)$old_data : [];
+ $old_data = isset($old_data) ? (array)$old_data : [];
}
?>
diff --git a/ext/opcache/tests/bug76477.phpt b/ext/opcache/tests/bug76477.phpt
index 39bff0d46c..7978ce4d7b 100644
--- a/ext/opcache/tests/bug76477.phpt
+++ b/ext/opcache/tests/bug76477.phpt
@@ -11,9 +11,9 @@ opcache.optimization_level=-1
testString();
function testString()
{
- $token = "ABC";
- $lengthBytes = strlenb($token);
- var_dump($lengthBytes == 0);
+ $token = "ABC";
+ $lengthBytes = strlenb($token);
+ var_dump($lengthBytes == 0);
}
function strlenb() { return call_user_func_array("strlen", func_get_args()); }
diff --git a/ext/opcache/tests/bug77058.phpt b/ext/opcache/tests/bug77058.phpt
index a1962b7ade..18d510bbde 100644
--- a/ext/opcache/tests/bug77058.phpt
+++ b/ext/opcache/tests/bug77058.phpt
@@ -3,7 +3,7 @@ Bug #77058: Type inference in opcache causes side effects
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
-<?php
+<?php
function myfunc(){
$Nr = 0;
@@ -18,5 +18,5 @@ myfunc();
?>
--EXPECTF--
-Notice: Undefined variable: x in %s on line %d
+Warning: Undefined variable: x in %s on line %d
'2' is expected to be 2
diff --git a/ext/opcache/tests/bug77191.phpt b/ext/opcache/tests/bug77191.phpt
index ca04b4aadd..ffbc90700c 100644
--- a/ext/opcache/tests/bug77191.phpt
+++ b/ext/opcache/tests/bug77191.phpt
@@ -3,13 +3,13 @@ Bug #77191: Assertion failure in dce_live_ranges() when silencing is used
--FILE--
<?php
function test($x) {
- switch (@$x['y']) {
- case 1: return 'a';
- case 2: return 'b';
- case 3: return 'c';
- case 4: return 'd';
- }
- return 'e';
+ switch (@$x['y']) {
+ case 1: return 'a';
+ case 2: return 'b';
+ case 3: return 'c';
+ case 4: return 'd';
+ }
+ return 'e';
}
var_dump(test([]));
?>
diff --git a/ext/opcache/tests/bug77266.phpt b/ext/opcache/tests/bug77266.phpt
index 8e225b8480..08fc74f96d 100644
--- a/ext/opcache/tests/bug77266.phpt
+++ b/ext/opcache/tests/bug77266.phpt
@@ -10,21 +10,21 @@ opcache.optimization_level=-1
<?php
final class Lock
{
- private static function clearOrphanedLocks()
- {
- $lockList = [];
+ private static function clearOrphanedLocks()
+ {
+ $lockList = [];
- $serverMonitors = array();
- $listCount = count($lockList);
- if ( is_array($lockList) && $listCount > 0 ) {
- $v = explode(':', $value);
- if (!$serverMonitors[$v[0]]['m']) {
- $serverMonitors[$v[0]]['m'] = new ServerMonitor($v[0]);
- }
+ $serverMonitors = array();
+ $listCount = count($lockList);
+ if ( is_array($lockList) && $listCount > 0 ) {
+ $v = explode(':', $value);
+ if (!$serverMonitors[$v[0]]['m']) {
+ $serverMonitors[$v[0]]['m'] = new ServerMonitor($v[0]);
+ }
- }
+ }
- }
+ }
}
?>
diff --git a/ext/opcache/tests/bug77743.phpt b/ext/opcache/tests/bug77743.phpt
index b73da2baaf..f9075a3a7f 100644
--- a/ext/opcache/tests/bug77743.phpt
+++ b/ext/opcache/tests/bug77743.phpt
@@ -6,12 +6,12 @@ Bug #77743: Incorrect pi node insertion for jmpznz with identical successors
<?php
function buggy($a) {
- $id_country = $a;
- if ($id_country === false) {
- if (true) {
- }
- }
- var_dump($id_country);
+ $id_country = $a;
+ if ($id_country === false) {
+ if (true) {
+ }
+ }
+ var_dump($id_country);
}
buggy(42);
diff --git a/ext/opcache/tests/bug78014.inc b/ext/opcache/tests/bug78014.inc
index 51a1196476..aed61ab743 100644
--- a/ext/opcache/tests/bug78014.inc
+++ b/ext/opcache/tests/bug78014.inc
@@ -1,4 +1,4 @@
-<?php
+<?php
class A {
function foo() { return 0; }
}
diff --git a/ext/opcache/tests/bug78015.phpt b/ext/opcache/tests/bug78015.phpt
index 0a03c9834f..aa4ba4db4b 100644
--- a/ext/opcache/tests/bug78015.phpt
+++ b/ext/opcache/tests/bug78015.phpt
@@ -103,7 +103,7 @@ array(1) {
}
bool(true)
-Notice: Array to string conversion in %s on line %d
+Warning: Array to string conversion in %s on line %d
string(11) "Arrayfoobar"
int(2)
array(2) {
diff --git a/ext/opcache/tests/bug78185.phpt b/ext/opcache/tests/bug78185.phpt
index 51a89f98d3..926bb96404 100644
--- a/ext/opcache/tests/bug78185.phpt
+++ b/ext/opcache/tests/bug78185.phpt
@@ -10,12 +10,12 @@ opcache.file_cache_only=1
--FILE--
<?php
if (substr(PHP_OS, 0, 3) !== 'WIN') {
- $pattern = __DIR__ . '/*/' . __DIR__ . '/*78185.php.bin';
+ $pattern = __DIR__ . '/*/' . __DIR__ . '/*78185.php.bin';
} else {
- $pattern = __DIR__ . '/*/*/' . str_replace(':', '', __DIR__) . '/*78185.php.bin';
+ $pattern = __DIR__ . '/*/*/' . str_replace(':', '', __DIR__) . '/*78185.php.bin';
}
foreach (glob($pattern) as $p) {
- var_dump($p);
+ var_dump($p);
}
?>
--CLEAN--
diff --git a/ext/opcache/tests/bug78986.phpt b/ext/opcache/tests/bug78986.phpt
index 9479460f76..420c828aa4 100644
--- a/ext/opcache/tests/bug78986.phpt
+++ b/ext/opcache/tests/bug78986.phpt
@@ -11,7 +11,7 @@ class TestClass2 {
class TestClass extends TestClass2 {
var $test = [
- TEST_TEST => 'test'
+ TEST_TEST => 'test'
];
}
diff --git a/ext/opcache/tests/compact_literals.phpt b/ext/opcache/tests/compact_literals.phpt
index 0aabb22b50..0963c27705 100644
--- a/ext/opcache/tests/compact_literals.phpt
+++ b/ext/opcache/tests/compact_literals.phpt
@@ -11,10 +11,10 @@ opcache.optimization_level=-1
echo "array key hash" . ":" . PHP_EOL;
$array = array(
- "1" => "one",
- "2" => "two",
- "one" => 1,
- "two" => 2,
+ "1" => "one",
+ "2" => "two",
+ "one" => 1,
+ "two" => 2,
);
unset($array["one"]);
@@ -24,9 +24,9 @@ print_r($array);
echo "function define" . ":" . PHP_EOL;
if (!function_exists("dummy")) {
- function dummy() {
- var_dump(__FUNCTION__);
- }
+ function dummy() {
+ var_dump(__FUNCTION__);
+ }
}
dummy();
@@ -35,22 +35,22 @@ $dummy = function () { var_dump("lambda" . "dummy"); };
$dummy();
if (!class_exists("A")) {
- class A {
- public static $name = "A";
- public static function say($n = "name") {
- var_dump(static::$name);
- }
- }
+ class A {
+ public static $name = "A";
+ public static function say($n = "name") {
+ var_dump(static::$name);
+ }
+ }
}
class B extends A {
- public static $name = "B";
+ public static $name = "B";
}
if (!class_exists("C")) {
- class C extends B {
- public static $name = "C";
- }
+ class C extends B {
+ public static $name = "C";
+ }
}
A::say();
@@ -60,7 +60,7 @@ B::say();
C::say();
function get_eol_define() {
- define("MY_EOL", PHP_EOL);
+ define("MY_EOL", PHP_EOL);
}
get_eol_define();
define("EOL", MY_EOL);
@@ -71,17 +71,17 @@ echo "define " . "TEST" . EOL;
define("TEST", "TEST");
class E {
- public static $E="EP";
- const E="E";
- const TEST="NULL";
+ public static $E="EP";
+ const E="E";
+ const TEST="NULL";
}
class F {
- const F="F";
- public static $E="FEP";
- const E="FE";
- const TEST="FALSE";
- public static $F = "FP";
+ const F="F";
+ public static $E="FEP";
+ const E="FE";
+ const TEST="FALSE";
+ public static $F = "FP";
}
var_dump(TEST); //"TEST"
@@ -97,25 +97,25 @@ var_dumP(F::$E); //"FEP"
echo "propertes and methods" . EOL;
class CH {
- const H = "H";
- public function h() {
- var_dump(self::H);
- }
+ const H = "H";
+ public function h() {
+ var_dump(self::H);
+ }
}
class CI {
- const H = "I";
- public function h() {
- var_dump(self::H);
- }
+ const H = "I";
+ public function h() {
+ var_dump(self::H);
+ }
}
function change(&$obj) {
- $obj = new CH;
+ $obj = new CH;
}
function geti() {
- return new CI;
+ return new CI;
}
$h = new CH;
diff --git a/ext/opcache/tests/issue0115.phpt b/ext/opcache/tests/issue0115.phpt
index bc86d0f4fc..b8df30a164 100644
--- a/ext/opcache/tests/issue0115.phpt
+++ b/ext/opcache/tests/issue0115.phpt
@@ -7,7 +7,6 @@ phar.readonly=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
<?php if (!extension_loaded("phar")) die("skip"); ?>
-<?php if (php_sapi_name() != "cli") die("skip CLI only"); ?>
--CONFLICTS--
server
--FILE--
diff --git a/ext/opcache/tests/issue0140.phpt b/ext/opcache/tests/issue0140.phpt
index 3ca9b50d3c..78f711fce9 100644
--- a/ext/opcache/tests/issue0140.phpt
+++ b/ext/opcache/tests/issue0140.phpt
@@ -7,7 +7,6 @@ opcache.revalidate_freq=0
opcache.file_update_protection=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
-<?php if (php_sapi_name() != "cli") die("skip CLI only"); ?>
<?php if (getenv("SKIP_SLOW_TESTS")) die("skip slow tests excluded by request") ?>
--FILE--
<?php
diff --git a/ext/opcache/tests/issue0149.phpt b/ext/opcache/tests/issue0149.phpt
index da3b778ef5..0896e39d0c 100644
--- a/ext/opcache/tests/issue0149.phpt
+++ b/ext/opcache/tests/issue0149.phpt
@@ -7,7 +7,6 @@ phar.readonly=0
--SKIPIF--
<?php require_once('skipif.inc'); ?>
<?php if (!extension_loaded("phar")) die("skip"); ?>
-<?php if (php_sapi_name() != "cli") die("skip CLI only"); ?>
--CONFLICTS--
server
--FILE--
diff --git a/ext/opcache/tests/issue0183.phpt b/ext/opcache/tests/issue0183.phpt
index 9e18f6d2e8..26da4d97cc 100644
--- a/ext/opcache/tests/issue0183.phpt
+++ b/ext/opcache/tests/issue0183.phpt
@@ -11,15 +11,15 @@ opcache.optimization_level=-1
<?php
switch (PHP_OS) {
- case "Windows":
- break;
- case "Darwin":
- break;
- case "Linux":
- echo "okey";
- break;
- default:
- break;
+ case "Windows":
+ break;
+ case "Darwin":
+ break;
+ case "Linux":
+ echo "okey";
+ break;
+ default:
+ break;
}
--EXPECT--
okey
diff --git a/ext/opcache/tests/jit/array_elem.phpt b/ext/opcache/tests/jit/array_elem.phpt
new file mode 100644
index 0000000000..542a872543
--- /dev/null
+++ b/ext/opcache/tests/jit/array_elem.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Refcount inference when adding array elements
+--FILE--
+<?php
+
+function test($a) {
+ $ary = [$a];
+ $ary2 = [0, $ary, $ary];
+ return $ary2;
+}
+var_dump(test(1));
+
+?>
+--EXPECT--
+array(3) {
+ [0]=>
+ int(0)
+ [1]=>
+ array(1) {
+ [0]=>
+ int(1)
+ }
+ [2]=>
+ array(1) {
+ [0]=>
+ int(1)
+ }
+}
diff --git a/ext/opcache/tests/jit/assign_001.phpt b/ext/opcache/tests/jit/assign_001.phpt
new file mode 100644
index 0000000000..959659cff1
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_001.phpt
@@ -0,0 +1,27 @@
+--TEST--
+JIT ASSIGN: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $b = $a;
+ $c = $a;
+ $a = 1;
+ $x = $a;
+ var_dump($x, $b, $c);
+}
+foo();
+--EXPECT--
+int(1)
+array(0) {
+}
+array(0) {
+}
diff --git a/ext/opcache/tests/jit/assign_002.phpt b/ext/opcache/tests/jit/assign_002.phpt
new file mode 100644
index 0000000000..355fdd4472
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_002.phpt
@@ -0,0 +1,29 @@
+--TEST--
+JIT ASSIGN: 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $ref1 = 2.3;
+ $ref2 =& $ref1;
+ $a = array();
+ $b = $a;
+ $c = $a;
+ $a = $ref1;
+ $x = $a;
+ var_dump($x, $b, $c);
+}
+foo();
+--EXPECT--
+float(2.3)
+array(0) {
+}
+array(0) {
+}
diff --git a/ext/opcache/tests/jit/assign_003.phpt b/ext/opcache/tests/jit/assign_003.phpt
new file mode 100644
index 0000000000..7e885d38aa
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_003.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 003
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array(); // [rc1, array]
+ $a = 1; // [rc1, long, reg]
+ $x = $a;
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(1)
diff --git a/ext/opcache/tests/jit/assign_004.phpt b/ext/opcache/tests/jit/assign_004.phpt
new file mode 100644
index 0000000000..70c25bc888
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_004.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 004
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = null;
+ $b = $a;
+ $c = null;
+ $d = $c;
+ $a = 1;
+ $c = $a;
+ return $c;
+}
+var_dump(foo());
+--EXPECT--
+int(1)
diff --git a/ext/opcache/tests/jit/assign_005.phpt b/ext/opcache/tests/jit/assign_005.phpt
new file mode 100644
index 0000000000..d3f9dca61c
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_005.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 005
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $b = $a;
+ $c = array();
+ $d = $c;
+ $a = 1;
+ $c = $a;
+ return $c;
+}
+var_dump(foo());
+--EXPECT--
+int(1)
diff --git a/ext/opcache/tests/jit/assign_006.phpt b/ext/opcache/tests/jit/assign_006.phpt
new file mode 100644
index 0000000000..6efc98fe0f
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_006.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT ASSIGN: 006
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $c = array();
+ $a = 1;
+ $c = $a;
+ return $c;
+}
+var_dump(foo());
+--EXPECT--
+int(1)
diff --git a/ext/opcache/tests/jit/assign_007.phpt b/ext/opcache/tests/jit/assign_007.phpt
new file mode 100644
index 0000000000..f54ede5ec5
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_007.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 007
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = 1.0;
+ $c = 2.0;
+ $a = 1;
+ var_dump($a);
+}
+foo();
+--EXPECT--
+int(1)
diff --git a/ext/opcache/tests/jit/assign_008.phpt b/ext/opcache/tests/jit/assign_008.phpt
new file mode 100644
index 0000000000..22b6a465f5
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_008.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 008
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = 1.0;
+ $c = 2.0;
+ $c = $a;
+ var_dump($a);
+}
+foo();
+--EXPECT--
+float(1)
diff --git a/ext/opcache/tests/jit/assign_009.phpt b/ext/opcache/tests/jit/assign_009.phpt
new file mode 100644
index 0000000000..6772e9028f
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_009.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 009
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $b = $a;
+ $a = $b;
+}
+foo();
+echo "ok\n";
+--EXPECT--
+ok
diff --git a/ext/opcache/tests/jit/assign_010.phpt b/ext/opcache/tests/jit/assign_010.phpt
new file mode 100644
index 0000000000..77886de67a
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_010.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 010
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $b =& $a;
+ $a = $b;
+}
+foo();
+echo "ok\n";
+--EXPECT--
+ok
diff --git a/ext/opcache/tests/jit/assign_011.phpt b/ext/opcache/tests/jit/assign_011.phpt
new file mode 100644
index 0000000000..dc9b5e756c
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_011.phpt
@@ -0,0 +1,28 @@
+--TEST--
+JIT ASSIGN: 011
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = 1;
+ $c = 2;
+ $d = 3;
+ if ($a) {
+ $b = array();
+ } else {
+ $b =& $c;
+ }
+ $b = $d;
+ var_dump($b, $c);
+}
+foo();
+--EXPECT--
+int(3)
+int(2)
diff --git a/ext/opcache/tests/jit/assign_012.phpt b/ext/opcache/tests/jit/assign_012.phpt
new file mode 100644
index 0000000000..82d42d9b46
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_012.phpt
@@ -0,0 +1,28 @@
+--TEST--
+JIT ASSIGN: 012
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = 0;
+ $c = 2;
+ $d = 3;
+ if ($a) {
+ $b = array();
+ } else {
+ $b =& $c;
+ }
+ $b = $d;
+ var_dump($b, $c);
+}
+foo();
+--EXPECT--
+int(3)
+int(3)
diff --git a/ext/opcache/tests/jit/assign_013.phpt b/ext/opcache/tests/jit/assign_013.phpt
new file mode 100644
index 0000000000..a2da0b34d8
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_013.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 013
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $b = 2;
+ $c = $a = $b;
+ var_dump($c);
+}
+foo();
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/assign_014.phpt b/ext/opcache/tests/jit/assign_014.phpt
new file mode 100644
index 0000000000..0313753aff
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_014.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT ASSIGN: 014
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = 1;
+ $b = array();
+ $c = $a = $b;
+ var_dump($c);
+}
+foo();
+--EXPECT--
+array(0) {
+}
diff --git a/ext/opcache/tests/jit/assign_015.phpt b/ext/opcache/tests/jit/assign_015.phpt
new file mode 100644
index 0000000000..248259e328
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_015.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 015
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = 1;
+ $b = 2;
+ $c = $a = $b;
+ var_dump($c);
+}
+foo();
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/assign_016.phpt b/ext/opcache/tests/jit/assign_016.phpt
new file mode 100644
index 0000000000..a2ba0e0a7f
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_016.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 016
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = 1;
+ $b = 2;
+ $c = $a = $b;
+ return $c;
+}
+var_dump(foo());
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/assign_017.phpt b/ext/opcache/tests/jit/assign_017.phpt
new file mode 100644
index 0000000000..7aafdefd70
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_017.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 017
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $b = 2;
+ $c = $a = $b;
+ return $c;
+}
+var_dump(foo());
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/assign_018.phpt b/ext/opcache/tests/jit/assign_018.phpt
new file mode 100644
index 0000000000..8b19921e28
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_018.phpt
@@ -0,0 +1,26 @@
+--TEST--
+JIT ASSIGN: 018
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $c = array();
+ $d = $c;
+ $a = 1;
+ $b = 2;
+ $c = $a = $b;
+ var_dump($c, $d);
+}
+foo();
+--EXPECT--
+int(2)
+array(0) {
+}
+
diff --git a/ext/opcache/tests/jit/assign_019.phpt b/ext/opcache/tests/jit/assign_019.phpt
new file mode 100644
index 0000000000..6c84c4fbad
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_019.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 019
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $c = array();
+ $d =& $c;
+ $a = 1;
+ $b = 2;
+ $c = $a = $b;
+ var_dump($c, $d);
+}
+foo();
+--EXPECT--
+int(2)
+int(2)
diff --git a/ext/opcache/tests/jit/assign_020.phpt b/ext/opcache/tests/jit/assign_020.phpt
new file mode 100644
index 0000000000..6d1ccc89b2
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_020.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT ASSIGN: 020
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $c = array();
+ $a = 1;
+ $b = 2;
+ $c = $a = $b;
+ var_dump($c);
+}
+foo();
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/assign_021.phpt b/ext/opcache/tests/jit/assign_021.phpt
new file mode 100644
index 0000000000..caad315d3e
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_021.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 021
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array();
+ $b = $a;
+ $c = 1;
+ $d = $a = $c;
+ var_dump($b, $d);
+}
+foo();
+--EXPECT--
+array(0) {
+}
+int(1)
diff --git a/ext/opcache/tests/jit/assign_022.phpt b/ext/opcache/tests/jit/assign_022.phpt
new file mode 100644
index 0000000000..8298c28b22
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_022.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 022
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array(1);
+ $a[0] = $undef;
+ for($i=0; $i<6; $i++) {
+ $undef = 1;
+ }
+}
+foo();
+echo "ok\n";
+--EXPECTF--
+Warning: Undefined variable: undef in %s on line %d
+ok
diff --git a/ext/opcache/tests/jit/assign_023.phpt b/ext/opcache/tests/jit/assign_023.phpt
new file mode 100644
index 0000000000..e1211f5569
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_023.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 023
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array(1);
+ $a = $undef;
+ for($i=0; $i<6; $i++) {
+ $undef = 1;
+ }
+}
+foo();
+echo "ok\n";
+--EXPECTF--
+Warning: Undefined variable: undef in %s on line %d
+ok
diff --git a/ext/opcache/tests/jit/assign_024.phpt b/ext/opcache/tests/jit/assign_024.phpt
new file mode 100644
index 0000000000..f77296f84d
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_024.phpt
@@ -0,0 +1,23 @@
+--TEST--
+JIT ASSIGN: 024
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = $undef;
+ for($i=0; $i<6; $i++) {
+ $undef = 1;
+ }
+}
+foo();
+echo "ok\n";
+--EXPECTF--
+Warning: Undefined variable: undef in %s on line %d
+ok
diff --git a/ext/opcache/tests/jit/assign_025.phpt b/ext/opcache/tests/jit/assign_025.phpt
new file mode 100644
index 0000000000..9bafa43cb6
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_025.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 025
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $arr[0][0] = $ref;
+ for($cnt=0;$cnt<6;$cnt++) {
+ $ref = 1;
+ $arr[0][0] = $ref;
+ }
+}
+foo();
+echo "ok\n";
+--EXPECTF--
+Warning: Undefined variable: ref in %s on line %d
+ok
diff --git a/ext/opcache/tests/jit/assign_026.phpt b/ext/opcache/tests/jit/assign_026.phpt
new file mode 100644
index 0000000000..160d066b51
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_026.phpt
@@ -0,0 +1,25 @@
+--TEST--
+JIT ASSIGN: 026
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array(1,2,3);
+ $b=&$a;
+ $b=1;
+ $a = new stdClass;
+ $a->a=1;
+ $a->b=2;
+ $b=&$a;
+}
+foo();
+echo "ok\n";
+--EXPECT--
+ok
diff --git a/ext/opcache/tests/jit/assign_027.phpt b/ext/opcache/tests/jit/assign_027.phpt
new file mode 100644
index 0000000000..a704e3cdd6
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_027.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT ASSIGN: 027
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $persons = 2;
+ for ($i=0; $i<$persons; $i++) {
+ $children = 2;
+ }
+}
+foo();
+echo "ok\n";
+--EXPECT--
+ok
diff --git a/ext/opcache/tests/jit/assign_028.phpt b/ext/opcache/tests/jit/assign_028.phpt
new file mode 100644
index 0000000000..95f076b206
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_028.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 028
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ var_dump($i=1);
+ return $i;
+}
+var_dump(foo());
+--EXPECT--
+int(1)
+int(1)
diff --git a/ext/opcache/tests/jit/assign_029.phpt b/ext/opcache/tests/jit/assign_029.phpt
new file mode 100644
index 0000000000..d79d235c7f
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_029.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT ASSIGN: 029
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $i = 1;
+ var_dump($i=2);
+ return $i;
+}
+var_dump(foo());
+--EXPECT--
+int(2)
+int(2)
diff --git a/ext/opcache/tests/jit/assign_030.phpt b/ext/opcache/tests/jit/assign_030.phpt
new file mode 100644
index 0000000000..4f87b10f11
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_030.phpt
@@ -0,0 +1,23 @@
+--TEST--
+JIT ASSIGN: 030
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $i = 1;
+ $x = 2;
+ var_dump($i=$x);
+ return $i;
+}
+var_dump(foo());
+--EXPECT--
+int(2)
+int(2)
diff --git a/ext/opcache/tests/jit/assign_031.phpt b/ext/opcache/tests/jit/assign_031.phpt
new file mode 100644
index 0000000000..7a2b3ad582
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_031.phpt
@@ -0,0 +1,19 @@
+--TEST--
+JIT ASSIGN: 031
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$c =& $a;
+$b = $a;
+echo "ok\n";
+?>
+--EXPECT--
+ok
diff --git a/ext/opcache/tests/jit/assign_032.phpt b/ext/opcache/tests/jit/assign_032.phpt
new file mode 100644
index 0000000000..448f924aed
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_032.phpt
@@ -0,0 +1,27 @@
+--TEST--
+JIT ASSIGN: 032
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$var = "intergalactic";
+$var1 = "space";
+$var2 = &$var1;
+$var = $var2;
+var_dump($var);
+var_dump($var1);
+var_dump($var2);
+echo "Done\n";
+?>
+--EXPECT--
+string(5) "space"
+string(5) "space"
+string(5) "space"
+Done
diff --git a/ext/opcache/tests/jit/assign_033.phpt b/ext/opcache/tests/jit/assign_033.phpt
new file mode 100644
index 0000000000..918f3b6b57
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_033.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT ASSIGN: 033
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo()
+{
+ $mode = 0;
+ $working = 0;
+ while ($mode == 0) {
+ $working = $mode = 1;
+ }
+}
+echo "ok\n";
+--EXPECT--
+ok
diff --git a/ext/opcache/tests/jit/assign_034.phpt b/ext/opcache/tests/jit/assign_034.phpt
new file mode 100644
index 0000000000..4fa7af3e9f
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_034.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT ASSIGN: 034
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function bar() {
+ $a = strlen("a");
+ $a++;
+ return $a;
+}
+var_dump(bar());
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/assign_035.phpt b/ext/opcache/tests/jit/assign_035.phpt
new file mode 100644
index 0000000000..aebefc4391
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_035.phpt
@@ -0,0 +1,39 @@
+--TEST--
+JIT ASSIGN: Segfault & memleak if no RC info
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+class A {
+
+ public function test() {
+ $closure = function() { return "string"; };
+
+ $arr = [
+ 'a' => $closure(),
+ 'b' => [$closure() => [],],
+ ];
+
+ $x = $arr;
+ unset($x['b'][$closure()]['d']);
+
+ $x = $arr;
+ $x['a'] = $closure();
+
+ return "okey";
+ }
+}
+
+$a = new A();
+echo $a->test();
+?>
+--EXPECT--
+okey
diff --git a/ext/opcache/tests/jit/assign_036.phpt b/ext/opcache/tests/jit/assign_036.phpt
new file mode 100644
index 0000000000..f7065f0d5e
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_036.phpt
@@ -0,0 +1,43 @@
+--TEST--
+JIT ASSIGN: Assign with INTERNED string(no RC)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class A {
+ public $result = "string";
+ function __set($propName, $propValue)
+ {
+ $oldType = \gettype($this->$propName);
+ $newType = \gettype($propValue);
+ if ($propValue === 'false')
+ {
+ $newType = 'boolean';
+ $propValue = \false;
+ }
+ elseif ($propValue === 'true')
+ {
+ $newType = 'boolean';
+ $propValue = \true;
+ }
+ if ($oldType !== $newType)
+ {
+ $tmp = $propValue;
+ \settype($tmp, $newType);
+ }
+ $this->propName = $propValue;
+ }
+}
+$a = new A;
+$a->result = "okey";
+echo $a->result;
+?>
+--EXPECT--
+okey
diff --git a/ext/opcache/tests/jit/assign_dim_002.phpt b/ext/opcache/tests/jit/assign_dim_002.phpt
new file mode 100644
index 0000000000..135df92123
--- /dev/null
+++ b/ext/opcache/tests/jit/assign_dim_002.phpt
@@ -0,0 +1,137 @@
+--TEST--
+JIT ASSIGN_DIM: 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $var[] = 1;
+ var_dump($var);
+}
+foo();
+
+function foo1() {
+ $var1[] = true;
+ var_dump($var1);
+}
+foo1();
+
+function foo2() {
+ $var2[] = array();
+ var_dump($var2);
+}
+foo2();
+
+function foo3() {
+ $array = array(PHP_INT_MAX => "dummy");
+ try {
+ $array[] = array();
+ } catch (Error $e) {
+ echo $e->getMessage(), "\n";
+ }
+
+ $array = new ArrayObject();
+ $array[index()] = 1;
+ $array[offset()] = 2;
+
+ var_dump($array);
+}
+foo3();
+
+function index() {
+ return 2;
+}
+
+function offset() {
+ return "a";
+}
+
+function foo4() {
+ $array = array();
+ $array[] = array();
+ $array[0][] = 1;
+ $array[0][1] = 1;
+ var_dump($array);
+
+ try {
+ $array[function() {}] = 2;
+ } catch (Error $e) {
+ echo $e->getMessage(), "\n";
+ }
+ var_dump($array);
+
+ $array2[][] = 3;
+ var_dump($array);
+}
+foo4();
+
+function foo5() {
+ $a = 1;
+ try {
+ $a[2] = 1;
+ } catch (Error $e) {
+ echo $e->getMessage(), "\n";
+ }
+ return $a;
+}
+var_dump(foo5());
+
+--EXPECTF--
+array(1) {
+ [0]=>
+ int(1)
+}
+array(1) {
+ [0]=>
+ bool(true)
+}
+array(1) {
+ [0]=>
+ array(0) {
+ }
+}
+Cannot add element to the array as the next element is already occupied
+object(ArrayObject)#%d (1) {
+ ["storage":"ArrayObject":private]=>
+ array(2) {
+ [2]=>
+ int(1)
+ ["a"]=>
+ int(2)
+ }
+}
+array(1) {
+ [0]=>
+ array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ }
+}
+Illegal offset type
+array(1) {
+ [0]=>
+ array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ }
+}
+array(1) {
+ [0]=>
+ array(2) {
+ [0]=>
+ int(1)
+ [1]=>
+ int(1)
+ }
+}
+Cannot use a scalar value as an array
+int(1)
diff --git a/ext/opcache/tests/jit/bug77857.phpt b/ext/opcache/tests/jit/bug77857.phpt
new file mode 100644
index 0000000000..9b9a80f533
--- /dev/null
+++ b/ext/opcache/tests/jit/bug77857.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Bug #77857 (Wrong result if executed with JIT)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=64
+opcache.jit=1205
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function test() {
+ $arr = array_fill(0, 1, 1.0);
+ $y = 0.0;
+ foreach ($arr as $v) {
+ $tmp = 1.0 * $v;
+ var_dump($tmp);
+ $y = $tmp/1.0;
+ }
+ return $y;
+}
+var_dump(test());
+?>
+--EXPECTF--
+float(1)
+float(1)
diff --git a/ext/opcache/tests/jit/cmp_001.phpt b/ext/opcache/tests/jit/cmp_001.phpt
new file mode 100644
index 0000000000..7cbe312ca1
--- /dev/null
+++ b/ext/opcache/tests/jit/cmp_001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT CMP: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$a = 0;
+$b = 0.0;
+var_dump($a < $b);
+var_dump($a > $b);
+var_dump($a <= $b);
+var_dump($a >= $b);
+?>
+--EXPECT--
+bool(false)
+bool(false)
+bool(true)
+bool(true)
diff --git a/ext/opcache/tests/jit/cmp_002.phpt b/ext/opcache/tests/jit/cmp_002.phpt
new file mode 100644
index 0000000000..8b02c975cd
--- /dev/null
+++ b/ext/opcache/tests/jit/cmp_002.phpt
@@ -0,0 +1,24 @@
+--TEST--
+JIT CMP: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$a = 0;
+$b = 0.0;
+var_dump($a < $b ? 1 : 0);
+var_dump($a > $b ? 1 : 0);
+var_dump($a <= $b ? 1 : 0);
+var_dump($a >= $b ? 1 : 0);
+?>
+--EXPECT--
+int(0)
+int(0)
+int(1)
+int(1)
diff --git a/ext/opcache/tests/jit/cmp_003.phpt b/ext/opcache/tests/jit/cmp_003.phpt
new file mode 100644
index 0000000000..60698dea04
--- /dev/null
+++ b/ext/opcache/tests/jit/cmp_003.phpt
@@ -0,0 +1,194 @@
+--TEST--
+JIT CMP: 003 Comparisoin with NaN
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function t() {
+ echo "!";
+ return true;
+}
+function f() {
+ echo "!";
+ return false;
+}
+$a = 0.0;
+$i = 0;
+$b = NAN;
+$c = true;
+$d = false;
+var_dump($a == $b);
+var_dump($a != $b);
+var_dump($a < $b);
+var_dump($a > $b);
+var_dump($a <= $b);
+var_dump($a >= $b);
+var_dump($a == $b ? 1 : 0);
+var_dump($a != $b ? 1 : 0);
+var_dump($a < $b ? 1 : 0);
+var_dump($a > $b ? 1 : 0);
+var_dump($a <= $b ? 1 : 0);
+var_dump($a >= $b ? 1 : 0);
+if ($a == $b) {
+} else {
+ echo "1\n";
+}
+if ($a != $b) {
+} else {
+ echo "2\n";
+}
+if ($a < $b) {
+} else {
+ echo "3\n";
+}
+if ($a > $b) {
+} else {
+ echo "4\n";
+}
+if ($a <= $b) {
+} else {
+ echo "5\n";
+}
+if ($a >= $b) {
+} else {
+ echo "6\n";
+}
+var_dump($i == $b ? 1 : 0);
+var_dump($i != $b ? 1 : 0);
+var_dump($i < $b ? 1 : 0);
+var_dump($i > $b ? 1 : 0);
+var_dump($i <= $b ? 1 : 0);
+var_dump($i >= $b ? 1 : 0);
+if ($i == $b) {
+} else {
+ echo "1\n";
+}
+if ($i != $b) {
+} else {
+ echo "2\n";
+}
+if ($i < $b) {
+} else {
+ echo "3\n";
+}
+if ($i > $b) {
+} else {
+ echo "4\n";
+}
+if ($i <= $b) {
+} else {
+ echo "5\n";
+}
+if ($i >= $b) {
+} else {
+ echo "6\n";
+}
+var_dump($a == $b && t());
+var_dump($a != $b && t());
+var_dump($a < $b && t());
+var_dump($a > $b && t());
+var_dump($a <= $b && t());
+var_dump($a >= $b && t());
+var_dump($a == $b || f());
+var_dump($a != $b || f());
+var_dump($a < $b || f());
+var_dump($a > $b || f());
+var_dump($a <= $b || f());
+var_dump($a >= $b || f());
+var_dump($i == $b && t());
+var_dump($i != $b && t());
+var_dump($i < $b && t());
+var_dump($i > $b && t());
+var_dump($i <= $b && t());
+var_dump($i >= $b && t());
+var_dump($i == $b || f());
+var_dump($i != $b || f());
+var_dump($i < $b || f());
+var_dump($i > $b || f());
+var_dump($i <= $b || f());
+var_dump($i >= $b || f());
+$a=NAN;
+var_dump($a == $b);
+var_dump($a != $b);
+var_dump($a < $b);
+var_dump($a > $b);
+var_dump($a <= $b);
+var_dump($a >= $b);
+var_dump($a == $b ? 1 : 0);
+var_dump($a != $b ? 1 : 0);
+var_dump($a < $b ? 1 : 0);
+var_dump($a > $b ? 1 : 0);
+var_dump($a <= $b ? 1 : 0);
+var_dump($a >= $b ? 1 : 0);
+?>
+--EXPECT--
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+int(0)
+int(1)
+int(0)
+int(0)
+int(0)
+int(0)
+1
+3
+4
+5
+6
+int(0)
+int(1)
+int(0)
+int(0)
+int(0)
+int(0)
+1
+3
+4
+5
+6
+bool(false)
+!bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+!bool(false)
+bool(true)
+!bool(false)
+!bool(false)
+!bool(false)
+!bool(false)
+bool(false)
+!bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+!bool(false)
+bool(true)
+!bool(false)
+!bool(false)
+!bool(false)
+!bool(false)
+bool(false)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
+int(0)
+int(1)
+int(0)
+int(0)
+int(0)
+int(0)
diff --git a/ext/opcache/tests/jit/cmp_004.phpt b/ext/opcache/tests/jit/cmp_004.phpt
new file mode 100644
index 0000000000..9a5772e378
--- /dev/null
+++ b/ext/opcache/tests/jit/cmp_004.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT CMP: 004 Comparisons inside conditional statement
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo(bool $test, int $x) {
+ if (($test ? $x >= 1 : $x > 1)) {
+ return 1;
+ }
+ return 0;
+}
+var_dump(foo(true, 9));
+?>
+--EXPECT--
+int(1)
diff --git a/ext/opcache/tests/jit/const_001.phpt b/ext/opcache/tests/jit/const_001.phpt
new file mode 100644
index 0000000000..67c9a0d121
--- /dev/null
+++ b/ext/opcache/tests/jit/const_001.phpt
@@ -0,0 +1,26 @@
+--TEST--
+JIT CONST: defined
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function define_const() {
+ define("CUSTOM_CONSTANT", 1);
+}
+function test_defined() {
+ var_dump(defined("CUSTOM_CONSTANT"));
+ define_const();
+ var_dump(defined("CUSTOM_CONSTANT"));
+}
+
+test_defined();
+?>
+--EXPECT--
+bool(false)
+bool(true)
diff --git a/ext/opcache/tests/jit/defined_001.phpt b/ext/opcache/tests/jit/defined_001.phpt
new file mode 100644
index 0000000000..76da7760c6
--- /dev/null
+++ b/ext/opcache/tests/jit/defined_001.phpt
@@ -0,0 +1,38 @@
+--TEST--
+JIT DEFINED: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.jit=1235
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo($i) {
+ $a = defined("X");
+ $b = defined("X");
+ if (defined("X")) {
+ $c = 1;
+ } else {
+ $c = 0;
+ }
+ if (!defined("X")) {
+ $d = 0;
+ } else {
+ $d = 1;
+ }
+ if ($a || $b || $c || $d) {
+
+ die("Error on $i-th iteration\n");
+ }
+
+}
+for ($i = 0; $i < 10000; $i++) {
+ foo($i);
+}
+echo "ok\n";
+?>
+--EXPECT--
+ok
diff --git a/ext/opcache/tests/jit/fetch_dim_func_args_001.phpt b/ext/opcache/tests/jit/fetch_dim_func_args_001.phpt
new file mode 100644
index 0000000000..b2e58c44b4
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_dim_func_args_001.phpt
@@ -0,0 +1,26 @@
+--TEST--
+JIT FETCH_DIM_FUNC_ARG: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+namespace A;
+
+class A {
+ public function change(array $config) {
+ $config['keys'] = array_keys($config["a"]);;
+ }
+}
+
+$a = new A();
+
+$a->change($a = array("a" => range(1, 5)));
+?>
+okey
+--EXPECT--
+okey
diff --git a/ext/opcache/tests/jit/fetch_dim_r_001.phpt b/ext/opcache/tests/jit/fetch_dim_r_001.phpt
new file mode 100644
index 0000000000..232f62cf75
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_dim_r_001.phpt
@@ -0,0 +1,45 @@
+--TEST--
+JIT FETCH_DIM_R: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = array(1,2,3,""=>4,"ab"=>5,"2x"=>6);
+ var_dump($a[0]);
+ var_dump($a[2]);
+ var_dump($a[1.0]);
+ var_dump($a["0"]);
+ var_dump($a["2"]);
+ var_dump($a[false]);
+ var_dump($a[true]);
+ var_dump($a[null]);
+ var_dump($a["ab"]);
+ $x = "a";
+ $y = "b";
+ var_dump($a[$x . $y]);
+ var_dump($a["2x"]);
+ $x = "2";
+ $y = "x";
+ var_dump($a[$x . $y]);
+}
+foo();
+--EXPECT--
+int(1)
+int(3)
+int(2)
+int(1)
+int(3)
+int(1)
+int(2)
+int(4)
+int(5)
+int(5)
+int(6)
+int(6)
diff --git a/ext/opcache/tests/jit/fetch_dim_r_002.phpt b/ext/opcache/tests/jit/fetch_dim_r_002.phpt
new file mode 100644
index 0000000000..178071b115
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_dim_r_002.phpt
@@ -0,0 +1,45 @@
+--TEST--
+JIT FETCH_DIM_R: 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo($n) {
+ $a = array(1,2,3,""=>4,"ab"=>5,"2x"=>6);
+ var_dump($a[$n]);
+}
+foo(0);
+foo(2);
+foo(1.0);
+foo("0");
+foo("2");
+foo(false);
+foo(true);
+foo(null);
+foo("ab");
+$x="a";
+$y="b";
+foo($x.$y);
+foo("2x");
+$x=2;
+$y="x";
+foo($x.$y);
+--EXPECT--
+int(1)
+int(3)
+int(2)
+int(1)
+int(3)
+int(1)
+int(2)
+int(4)
+int(5)
+int(5)
+int(6)
+int(6)
diff --git a/ext/opcache/tests/jit/fetch_dim_r_003.phpt b/ext/opcache/tests/jit/fetch_dim_r_003.phpt
new file mode 100644
index 0000000000..2638715236
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_dim_r_003.phpt
@@ -0,0 +1,61 @@
+--TEST--
+JIT FETCH_DIM_R: 003
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a = "ABCDEF";
+ var_dump($a[0]);
+ var_dump($a[2]);
+ var_dump($a[1.0]);
+ var_dump($a["0"]);
+ var_dump($a["2"]);
+ var_dump($a[false]);
+ var_dump($a[true]);
+ var_dump($a[null]);
+ var_dump($a["ab"]);
+ $x = "a";
+ $y = "b";
+ var_dump($a[$x . $y]);
+ var_dump($a["2x"]);
+ $x = "2";
+ $y = "x";
+ var_dump($a[$x . $y]);
+}
+foo();
+--EXPECTF--
+string(1) "A"
+string(1) "C"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "B"
+string(1) "A"
+string(1) "C"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "A"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "B"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "A"
+
+Warning: Illegal string offset 'ab' in %sfetch_dim_r_003.php on line 12
+string(1) "A"
+
+Warning: Illegal string offset 'ab' in %sfetch_dim_r_003.php on line 15
+string(1) "A"
+
+Notice: A non well formed numeric value encountered in %sfetch_dim_r_003.php on line 16
+string(1) "C"
+
+Notice: A non well formed numeric value encountered in %sfetch_dim_r_003.php on line 19
+string(1) "C"
diff --git a/ext/opcache/tests/jit/fetch_dim_r_004.phpt b/ext/opcache/tests/jit/fetch_dim_r_004.phpt
new file mode 100644
index 0000000000..0fd705942e
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_dim_r_004.phpt
@@ -0,0 +1,61 @@
+--TEST--
+JIT FETCH_DIM_R: 004
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo($n) {
+ $a = "ABCDEF";
+ var_dump($a[$n]);
+}
+foo(0);
+foo(2);
+foo(1.0);
+foo("0");
+foo("2");
+foo(false);
+foo(true);
+foo(null);
+foo("ab");
+$x="a";
+$y="b";
+foo($x.$y);
+foo("2x");
+$x=2;
+$y="x";
+foo($x.$y);
+--EXPECTF--
+string(1) "A"
+string(1) "C"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "B"
+string(1) "A"
+string(1) "C"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "A"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "B"
+
+Warning: String offset cast occurred in %s on line %d
+string(1) "A"
+
+Warning: Illegal string offset 'ab' in %sfetch_dim_r_004.php on line 4
+string(1) "A"
+
+Warning: Illegal string offset 'ab' in %sfetch_dim_r_004.php on line 4
+string(1) "A"
+
+Notice: A non well formed numeric value encountered in %sfetch_dim_r_004.php on line 4
+string(1) "C"
+
+Notice: A non well formed numeric value encountered in %sfetch_dim_r_004.php on line 4
+string(1) "C"
diff --git a/ext/opcache/tests/jit/fetch_dim_rw_001.phpt b/ext/opcache/tests/jit/fetch_dim_rw_001.phpt
new file mode 100644
index 0000000000..39b9fd33ff
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_dim_rw_001.phpt
@@ -0,0 +1,27 @@
+--TEST--
+JIT FETCH_DIM_RW: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $a[0][0] += 2;
+ return $a[0];
+}
+var_dump(foo());
+--EXPECTF--
+Warning: Undefined variable: a in %s on line %d
+
+Notice: Undefined offset: 0 in %sfetch_dim_rw_001.php on line 3
+
+Notice: Undefined offset: 0 in %sfetch_dim_rw_001.php on line 3
+array(1) {
+ [0]=>
+ int(2)
+}
diff --git a/ext/opcache/tests/jit/fetch_obj_001.phpt b/ext/opcache/tests/jit/fetch_obj_001.phpt
new file mode 100644
index 0000000000..d309442187
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_obj_001.phpt
@@ -0,0 +1,137 @@
+--TEST--
+JIT: FETCH_OBJ
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo(&$a) {
+ $a = 2;
+}
+
+function foo2(&$a) {
+ $a = array();
+}
+
+function foo3(&$a, $var) {
+ $a = $var;
+}
+
+$obj = new stdClass;
+foo($obj->a);
+var_dump($obj);
+foo2($obj->b);
+var_dump($obj);
+foo3($obj->a, "2" . "3");
+foo3($obj->a, $obj->b);
+var_dump($obj);
+
+$a = &$obj->a;
+$a = fopen(__FILE__, "r");
+var_dump($obj);
+
+function bar() {
+ $obj = new stdClass;
+ foo($obj->a);
+ var_dump($obj);
+ foo2($obj->b);
+ var_dump($obj);
+ foo3($obj->a, "2" . "3");
+ foo3($obj->a, $obj->b);
+ var_dump($obj);
+
+ $a = &$obj->a;
+ $a = fopen(__FILE__, "r");
+ var_dump($obj);
+
+ $d = array();
+ try {
+ foo($d->{"ab" ."c"});
+ } catch (Error $err) {
+ echo $err->getMessage(), "\n";
+ }
+ var_dump($d);
+
+ $e = NULL;
+ try {
+ foo($e->{"ab" ."c"});
+ } catch (Error $err) {
+ echo $err->getMessage(), "\n";
+ }
+ var_dump($e);
+
+ $f = "";
+ try {
+ foo($f->{"ab" ."c"});
+ } catch (Error $err) {
+ echo $err->getMessage(), "\n";
+ }
+ var_dump($f);
+}
+
+bar();
+?>
+--EXPECTF--
+object(stdClass)#%d (1) {
+ ["a"]=>
+ int(2)
+}
+object(stdClass)#%d (2) {
+ ["a"]=>
+ int(2)
+ ["b"]=>
+ array(0) {
+ }
+}
+object(stdClass)#%d (2) {
+ ["a"]=>
+ array(0) {
+ }
+ ["b"]=>
+ array(0) {
+ }
+}
+object(stdClass)#%d (2) {
+ ["a"]=>
+ &resource(5) of type (stream)
+ ["b"]=>
+ array(0) {
+ }
+}
+object(stdClass)#%d (1) {
+ ["a"]=>
+ int(2)
+}
+object(stdClass)#%d (2) {
+ ["a"]=>
+ int(2)
+ ["b"]=>
+ array(0) {
+ }
+}
+object(stdClass)#%d (2) {
+ ["a"]=>
+ array(0) {
+ }
+ ["b"]=>
+ array(0) {
+ }
+}
+object(stdClass)#%d (2) {
+ ["a"]=>
+ &resource(6) of type (stream)
+ ["b"]=>
+ array(0) {
+ }
+}
+Attempt to modify property 'abc' of non-object
+array(0) {
+}
+Attempt to modify property 'abc' of non-object
+NULL
+Attempt to modify property 'abc' of non-object
+string(0) ""
diff --git a/ext/opcache/tests/jit/fetch_obj_002.phpt b/ext/opcache/tests/jit/fetch_obj_002.phpt
new file mode 100644
index 0000000000..463ff01b26
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_obj_002.phpt
@@ -0,0 +1,41 @@
+--TEST--
+JIT: FETCH_OBJ 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class A {
+ public $x = 2;
+}
+
+class B {
+ public $x = 3;
+ public function __get($name) {
+ var_dump("__get");
+ }
+}
+
+function bar() {
+ $a = new A();
+ var_dump($a->x);
+ var_dump($a->y);
+ $b = new B();
+ var_dump($b->x);
+ unset($b->x);
+ $b->x;
+}
+
+bar();
+?>
+--EXPECTF--
+int(2)
+
+Warning: Undefined property: A::$y in %s on line %d
+NULL
+int(3)
+string(5) "__get"
diff --git a/ext/opcache/tests/jit/fetch_obj_003.phpt b/ext/opcache/tests/jit/fetch_obj_003.phpt
new file mode 100644
index 0000000000..de51b45fa7
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_obj_003.phpt
@@ -0,0 +1,46 @@
+--TEST--
+JIT: FETCH_OBJ 003
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class C {
+ var $a = 0;
+}
+function foo() {
+ $x = new C;
+ $x->a = 1;
+ unset($x->a);
+ $x->a += 2;
+ var_dump($x);
+}
+function bar() {
+ $x = new C;
+ $x->a = 1;
+ $x->b = 2;
+ unset($x->a);
+ $x->a += 2;
+ var_dump($x);
+}
+foo();
+bar();
+?>
+--EXPECTF--
+Warning: Undefined property: C::$a in %s on line %d
+object(C)#1 (1) {
+ ["a"]=>
+ int(2)
+}
+
+Warning: Undefined property: C::$a in %s on line %d
+object(C)#1 (2) {
+ ["a"]=>
+ int(2)
+ ["b"]=>
+ int(2)
+}
diff --git a/ext/opcache/tests/jit/fetch_obj_004.phpt b/ext/opcache/tests/jit/fetch_obj_004.phpt
new file mode 100644
index 0000000000..ec4d74f0e6
--- /dev/null
+++ b/ext/opcache/tests/jit/fetch_obj_004.phpt
@@ -0,0 +1,43 @@
+--TEST--
+JIT: FETCH_OBJ 004
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class C {
+ var $a = 0;
+}
+function foo() {
+ $x = new C;
+ $x->a = 1;
+ unset($x->a);
+ $x->a = 3;
+ var_dump($x);
+}
+function bar() {
+ $x = new C;
+ $x->a = 1;
+ $x->b = 2;
+ unset($x->a);
+ $x->a = 3;
+ var_dump($x);
+}
+foo();
+bar();
+?>
+--EXPECT--
+object(C)#1 (1) {
+ ["a"]=>
+ int(3)
+}
+object(C)#1 (2) {
+ ["a"]=>
+ int(3)
+ ["b"]=>
+ int(2)
+}
diff --git a/ext/opcache/tests/jit/inc_001.phpt b/ext/opcache/tests/jit/inc_001.phpt
new file mode 100644
index 0000000000..c3807303e7
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_001.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT INC: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ $x += 0;
+ ++$x; // mem -> mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/inc_002.phpt b/ext/opcache/tests/jit/inc_002.phpt
new file mode 100644
index 0000000000..4d2757ca75
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_002.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT INC: 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ ++$x; // reg -> mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/inc_003.phpt b/ext/opcache/tests/jit/inc_003.phpt
new file mode 100644
index 0000000000..9842527be7
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_003.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT INC: 003
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ $x += 0;
+ ++$x; // mem -> reg
+ return $x;
+}
+var_dump(foo());
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/inc_004.phpt b/ext/opcache/tests/jit/inc_004.phpt
new file mode 100644
index 0000000000..6431020537
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_004.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT INC: 004
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ ++$x; // reg -> reg
+ return $x;
+}
+var_dump(foo());
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/inc_005.phpt b/ext/opcache/tests/jit/inc_005.phpt
new file mode 100644
index 0000000000..d784b092e9
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_005.phpt
@@ -0,0 +1,23 @@
+--TEST--
+JIT INC: 005
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ $x += 0;
+ var_dump(++$x); // mem -> mem, mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(2)
+int(2)
diff --git a/ext/opcache/tests/jit/inc_006.phpt b/ext/opcache/tests/jit/inc_006.phpt
new file mode 100644
index 0000000000..3ecff9e13d
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_006.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT INC: 006
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ var_dump(++$x); // reg -> mem, mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+int(2)
+int(2)
diff --git a/ext/opcache/tests/jit/inc_007.phpt b/ext/opcache/tests/jit/inc_007.phpt
new file mode 100644
index 0000000000..bb1634d731
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_007.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT INC: 007
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ $x += 0;
+ return ++$x; // mem -> reg, reg
+}
+var_dump(foo());
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/inc_008.phpt b/ext/opcache/tests/jit/inc_008.phpt
new file mode 100644
index 0000000000..d008cb094d
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_008.phpt
@@ -0,0 +1,20 @@
+--TEST--
+JIT INC: 008
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1;
+ return ++$x; // reg -> reg, reg
+}
+var_dump(foo());
+--EXPECT--
+int(2)
diff --git a/ext/opcache/tests/jit/inc_009.phpt b/ext/opcache/tests/jit/inc_009.phpt
new file mode 100644
index 0000000000..e600cba7ad
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_009.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT INC: 009
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ $x += 0;
+ ++$x; // mem -> mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+float(2)
diff --git a/ext/opcache/tests/jit/inc_010.phpt b/ext/opcache/tests/jit/inc_010.phpt
new file mode 100644
index 0000000000..105387d924
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_010.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT INC: 010
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ ++$x; // reg -> mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+float(2)
diff --git a/ext/opcache/tests/jit/inc_011.phpt b/ext/opcache/tests/jit/inc_011.phpt
new file mode 100644
index 0000000000..d91c487965
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_011.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT INC: 011
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ $x += 0;
+ ++$x; // mem -> reg
+ return $x;
+}
+var_dump(foo());
+--EXPECT--
+float(2)
diff --git a/ext/opcache/tests/jit/inc_012.phpt b/ext/opcache/tests/jit/inc_012.phpt
new file mode 100644
index 0000000000..14fb5c1b90
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_012.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT INC: 012
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ ++$x; // reg -> reg
+ return $x;
+}
+var_dump(foo());
+--EXPECT--
+float(2)
diff --git a/ext/opcache/tests/jit/inc_013.phpt b/ext/opcache/tests/jit/inc_013.phpt
new file mode 100644
index 0000000000..2c2e5f0920
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_013.phpt
@@ -0,0 +1,23 @@
+--TEST--
+JIT INC: 013
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ $x += 0;
+ var_dump(++$x); // mem -> mem, mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+float(2)
+float(2)
diff --git a/ext/opcache/tests/jit/inc_014.phpt b/ext/opcache/tests/jit/inc_014.phpt
new file mode 100644
index 0000000000..e6f31f32f3
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_014.phpt
@@ -0,0 +1,22 @@
+--TEST--
+JIT INC: 014
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ var_dump(++$x); // reg -> mem, mem
+ var_dump($x);
+}
+foo();
+--EXPECT--
+float(2)
+float(2)
diff --git a/ext/opcache/tests/jit/inc_015.phpt b/ext/opcache/tests/jit/inc_015.phpt
new file mode 100644
index 0000000000..d841dc0c9c
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_015.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT INC: 015
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ $x += 0;
+ return ++$x; // mem -> reg, reg
+}
+var_dump(foo());
+--EXPECT--
+float(2)
diff --git a/ext/opcache/tests/jit/inc_016.phpt b/ext/opcache/tests/jit/inc_016.phpt
new file mode 100644
index 0000000000..c1a6302e92
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_016.phpt
@@ -0,0 +1,20 @@
+--TEST--
+JIT INC: 016
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = 1.0;
+ return ++$x; // reg -> reg, reg
+}
+var_dump(foo());
+--EXPECT--
+float(2)
diff --git a/ext/opcache/tests/jit/inc_017.phpt b/ext/opcache/tests/jit/inc_017.phpt
new file mode 100644
index 0000000000..c52e018048
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_017.phpt
@@ -0,0 +1,20 @@
+--TEST--
+JIT INC: 017
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = true;
+ return ++$x; // reg -> reg, reg
+}
+var_dump(foo());
+--EXPECT--
+bool(true)
diff --git a/ext/opcache/tests/jit/inc_018.phpt b/ext/opcache/tests/jit/inc_018.phpt
new file mode 100644
index 0000000000..c992fa528d
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_018.phpt
@@ -0,0 +1,20 @@
+--TEST--
+JIT INC: 018
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $x = false;
+ return ++$x; // reg -> reg, reg
+}
+var_dump(foo());
+--EXPECT--
+bool(false)
diff --git a/ext/opcache/tests/jit/inc_019.phpt b/ext/opcache/tests/jit/inc_019.phpt
new file mode 100644
index 0000000000..e147ef6f2f
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_019.phpt
@@ -0,0 +1,27 @@
+--TEST--
+JIT INC: 019
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function bar($b) {
+ if ($b) {
+ $a = 1;
+ } else {
+ $a = 2;
+ }
+ isset($a);
+ var_dump($a++);
+ return $a;
+}
+var_dump(bar(0));
+--EXPECT--
+int(2)
+int(3)
diff --git a/ext/opcache/tests/jit/inc_020.phpt b/ext/opcache/tests/jit/inc_020.phpt
new file mode 100644
index 0000000000..5b3530d6e1
--- /dev/null
+++ b/ext/opcache/tests/jit/inc_020.phpt
@@ -0,0 +1,28 @@
+--TEST--
+JIT INC: 020
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo($row) {
+ foreach ($row as $key => $value) {
+ if (is_int($key)) {
+ $key++;
+ }
+ if (isset($row[$key])) {
+ return false;
+ }
+ }
+ return true;
+}
+?>
+OK
+--EXPECT--
+OK \ No newline at end of file
diff --git a/ext/opcache/tests/jit/jmpz_001.phpt b/ext/opcache/tests/jit/jmpz_001.phpt
new file mode 100644
index 0000000000..2772942f39
--- /dev/null
+++ b/ext/opcache/tests/jit/jmpz_001.phpt
@@ -0,0 +1,26 @@
+--TEST--
+JIT JMPZ: JMPZ may require code for "smart branch" and at the same time be a target of another JMP.
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+namespace A;
+
+function test() {
+
+ $modelData = array();
+ $ret = false ||
+ ((is_array($modelData) || $modelData instanceof \Countable) && true) || false;
+ return $ret;
+}
+
+var_dump(test());
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/opcache/tests/jit/jmpz_ex_001.phpt b/ext/opcache/tests/jit/jmpz_ex_001.phpt
new file mode 100644
index 0000000000..c001fb9b69
--- /dev/null
+++ b/ext/opcache/tests/jit/jmpz_ex_001.phpt
@@ -0,0 +1,32 @@
+--TEST--
+JIT JMPZ_EX: Operand needs to be freed even if same as result
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class Test {
+ public $prop;
+ public function method() {
+ return $this->prop && $this->prop->method2();
+ }
+}
+
+class Test2 {
+ public function method2() {
+ return true;
+ }
+};
+
+$test = new Test;
+$test->prop = new Test2;
+var_dump($test->method());
+
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/opcache/tests/jit/mod_001.phpt b/ext/opcache/tests/jit/mod_001.phpt
new file mode 100644
index 0000000000..d9dd638f63
--- /dev/null
+++ b/ext/opcache/tests/jit/mod_001.phpt
@@ -0,0 +1,41 @@
+--TEST--
+JIT MOD: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function mod(int $a, int $b) {
+ return $a % $b;
+}
+var_dump(mod(125, 33));
+var_dump(mod(125, 32));
+var_dump(mod(-125, 33));
+var_dump(mod(-125, 32));
+var_dump(mod(125, -33));
+var_dump(mod(-125, -33));
+try {
+ var_dump(mod(125, -1));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(mod(125, 0));
+} catch (Throwable $e) {
+ echo "Exception (" . get_class($e) . "): " . $e->getMessage() . "\n";
+}
+?>
+--EXPECT--
+int(26)
+int(29)
+int(-26)
+int(-29)
+int(26)
+int(-26)
+int(0)
+Exception (DivisionByZeroError): Modulo by zero
diff --git a/ext/opcache/tests/jit/mod_002.phpt b/ext/opcache/tests/jit/mod_002.phpt
new file mode 100644
index 0000000000..9dada5e400
--- /dev/null
+++ b/ext/opcache/tests/jit/mod_002.phpt
@@ -0,0 +1,53 @@
+--TEST--
+JIT MOD: 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function mod33(int $a) {
+ return $a % 33;
+}
+function mod32(int $a) {
+ return $a % 32;
+}
+function modNeg33(int $a) {
+ return $a % -33;
+}
+function modNeg1(int $a) {
+ return $a % -1;
+}
+function mod0(int $a) {
+ return $a % 0;
+}
+var_dump(mod33(125));
+var_dump(mod32(125));
+var_dump(mod33(-125));
+var_dump(mod32(-125));
+var_dump(modNeg33(125));
+var_dump(modNeg33(-125));
+try {
+ var_dump(modNeg1(125));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(mod0(125));
+} catch (Throwable $e) {
+ echo "Exception (" . get_class($e) . "): " . $e->getMessage() . "\n";
+}
+?>
+--EXPECT--
+int(26)
+int(29)
+int(-26)
+int(-29)
+int(26)
+int(-26)
+int(0)
+Exception (DivisionByZeroError): Modulo by zero
diff --git a/ext/opcache/tests/jit/noval_001.phpt b/ext/opcache/tests/jit/noval_001.phpt
new file mode 100644
index 0000000000..f3aa4a0d0e
--- /dev/null
+++ b/ext/opcache/tests/jit/noval_001.phpt
@@ -0,0 +1,34 @@
+--TEST--
+JIT NOVAL: 001 (bug in zend_jit_compute_false_dependencies())
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class Foo {
+ const X = false;
+
+ static function bar() {
+ $count = 0;
+ if (self::X) {
+ $count = intval(9223372036854775807);
+ }
+ if (self::X) {
+ $count = 2;
+ }
+ if ($count != 0) {
+ return "bug";
+ }
+ return "ok";
+ }
+}
+var_dump(Foo::bar());
+--EXPECT--
+string(2) "ok"
+
diff --git a/ext/opcache/tests/jit/recv_001.phpt b/ext/opcache/tests/jit/recv_001.phpt
new file mode 100644
index 0000000000..2213da5f57
--- /dev/null
+++ b/ext/opcache/tests/jit/recv_001.phpt
@@ -0,0 +1,23 @@
+--TEST--
+JIT RECV: infinite loop
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+function test(array $args, $short_options, $long_options = null)
+{
+ echo "okey";
+}
+
+test(array(), "d:e", 222, 3434);
+
+--EXPECT--
+okey
diff --git a/ext/opcache/tests/jit/reg_alloc_001.phpt b/ext/opcache/tests/jit/reg_alloc_001.phpt
new file mode 100644
index 0000000000..609ed8e27f
--- /dev/null
+++ b/ext/opcache/tests/jit/reg_alloc_001.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Register Alloction 001: Spilling in "identical" code
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class Caster
+{
+ const EXCLUDE_PUBLIC = 8;
+ const EXCLUDE_PRIVATE = 32;
+ const EXCLUDE_STRICT = 512;
+
+ public static function filter(array $a, $filter)
+ {
+ foreach ($a as $k => $v) {
+ if (!isset($k[1])) {
+ $type |= self::EXCLUDE_PUBLIC;
+ } else {
+ $type |= self::EXCLUDE_PRIVATE;
+ }
+
+ if ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) {
+ }
+ }
+
+ return $a;
+ }
+
+}
+?>
+OK
+--EXPECT--
+OK
diff --git a/ext/opcache/tests/jit/reg_alloc_002.phpt b/ext/opcache/tests/jit/reg_alloc_002.phpt
new file mode 100644
index 0000000000..5593156188
--- /dev/null
+++ b/ext/opcache/tests/jit/reg_alloc_002.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Register Alloction 002: SEND_VAL_EX uses %r0 as a temporary register
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class A {
+ public function process($call) {
+ $i = 0;
+ foreach (array("a", "b", "c") as $attr) {
+ $call($i++, "xxx");
+ }
+ }
+}
+
+$a = new A();
+$a->process(function($i, $v) { var_dump($i); });
+?>
+--EXPECT--
+int(0)
+int(1)
+int(2)
diff --git a/ext/opcache/tests/jit/reg_alloc_003.phpt b/ext/opcache/tests/jit/reg_alloc_003.phpt
new file mode 100644
index 0000000000..f1a90dcec4
--- /dev/null
+++ b/ext/opcache/tests/jit/reg_alloc_003.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Register Alloction 003: Reuse temporary register
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function test($char_code) {
+ if ($char_code == !($char_code & 0xffffff80)) {
+ return "correct";
+ } else {
+ return "wrong";
+ }
+}
+echo test(65), "\n";
+?>
+--EXPECT--
+correct
diff --git a/ext/opcache/tests/jit/send_val_001.phpt b/ext/opcache/tests/jit/send_val_001.phpt
new file mode 100644
index 0000000000..8220b36f1a
--- /dev/null
+++ b/ext/opcache/tests/jit/send_val_001.phpt
@@ -0,0 +1,23 @@
+--TEST--
+JIT SEND_VAL: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo($type) {
+ $key = md5(
+ is_array($type) ? \implode('_', $type) : $type .
+ "ops"
+ );
+ return $key;
+}
+var_dump(foo("int"));
+var_dump(foo(["int"]));
+--EXPECT--
+string(32) "253a948ecc9192cb47e492f692aa63a8"
+string(32) "fa7153f7ed1cb6c0fcf2ffb2fac21748"
diff --git a/ext/opcache/tests/jit/send_var_ex_001.phpt b/ext/opcache/tests/jit/send_var_ex_001.phpt
new file mode 100644
index 0000000000..176f7502f5
--- /dev/null
+++ b/ext/opcache/tests/jit/send_var_ex_001.phpt
@@ -0,0 +1,30 @@
+--TEST--
+JIT SEND_VAR_EX fails on SHOULD_SEND_BY_REF checking
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+;opcache.jit_debug=257
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+namespace A;
+
+class A {
+ private $evalParameters;
+ public function evaluate() {
+ $this->evalParameters = array("a" => "okey");
+ extract($this->evalParameters, EXTR_SKIP);
+ echo $a;
+ return false;
+ }
+}
+
+$a = new A();
+
+$a->evaluate();
+?>
+--EXPECT--
+okey
diff --git a/ext/opcache/tests/jit/shift_left_001.phpt b/ext/opcache/tests/jit/shift_left_001.phpt
new file mode 100644
index 0000000000..4447d0943e
--- /dev/null
+++ b/ext/opcache/tests/jit/shift_left_001.phpt
@@ -0,0 +1,37 @@
+--TEST--
+JIT Shift Left: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function shl(int $a, int $b) {
+ return $a << $b;
+}
+var_dump(shl(1, 0));
+var_dump(shl(1, 1));
+var_dump(shl(1, 2));
+var_dump(shl(-1, 2));
+try {
+ var_dump(shl(1, 64));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(shl(1, -1));
+} catch (Throwable $e) {
+ echo "Exception (" . get_class($e) . "): " . $e->getMessage() . "\n";
+}
+?>
+--EXPECT--
+int(1)
+int(2)
+int(4)
+int(-4)
+int(0)
+Exception (ArithmeticError): Bit shift by negative number
diff --git a/ext/opcache/tests/jit/shift_left_002.phpt b/ext/opcache/tests/jit/shift_left_002.phpt
new file mode 100644
index 0000000000..a6478373b9
--- /dev/null
+++ b/ext/opcache/tests/jit/shift_left_002.phpt
@@ -0,0 +1,49 @@
+--TEST--
+JIT Shift Left: 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function shl0(int $a) {
+ return $a << 0;
+}
+function shl1(int $a) {
+ return $a << 1;
+}
+function shl2(int $a) {
+ return $a << 2;
+}
+function shl64(int $a) {
+ return $a << 64;
+}
+function shlNEG(int $a) {
+ return $a << -1;
+}
+var_dump(shl0(1));
+var_dump(shl1(1));
+var_dump(shl2(1));
+var_dump(shl2(-1));
+try {
+ var_dump(shl64(1));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(shlNEG(1));
+} catch (Throwable $e) {
+ echo "Exception (" . get_class($e) . "): " . $e->getMessage() . "\n";
+}
+?>
+--EXPECT--
+int(1)
+int(2)
+int(4)
+int(-4)
+int(0)
+Exception (ArithmeticError): Bit shift by negative number
diff --git a/ext/opcache/tests/jit/shift_right_001.phpt b/ext/opcache/tests/jit/shift_right_001.phpt
new file mode 100644
index 0000000000..01a547b9ea
--- /dev/null
+++ b/ext/opcache/tests/jit/shift_right_001.phpt
@@ -0,0 +1,43 @@
+--TEST--
+JIT Shift Right: 001
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function shr(int $a, int $b) {
+ return $a >> $b;
+}
+var_dump(shr(256, 0));
+var_dump(shr(256, 1));
+var_dump(shr(256, 2));
+var_dump(shr(-8, 2));
+try {
+ var_dump(shr(1, 64));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(shr(-1, 64));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(shr(1, -1));
+} catch (Throwable $e) {
+ echo "Exception (" . get_class($e) . "): " . $e->getMessage() . "\n";
+}
+?>
+--EXPECT--
+int(256)
+int(128)
+int(64)
+int(-2)
+int(0)
+int(-1)
+Exception (ArithmeticError): Bit shift by negative number
diff --git a/ext/opcache/tests/jit/shift_right_002.phpt b/ext/opcache/tests/jit/shift_right_002.phpt
new file mode 100644
index 0000000000..3d86a08116
--- /dev/null
+++ b/ext/opcache/tests/jit/shift_right_002.phpt
@@ -0,0 +1,55 @@
+--TEST--
+JIT Shift Right: 002
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function shr0(int $a) {
+ return $a >> 0;
+}
+function shr1(int $a) {
+ return $a >> 1;
+}
+function shr2(int $a) {
+ return $a >> 2;
+}
+function shr64(int $a) {
+ return $a >> 64;
+}
+function shrNEG(int $a) {
+ return $a >> -1;
+}
+var_dump(shr0(256));
+var_dump(shr1(256));
+var_dump(shr2(256));
+var_dump(shr2(-8));
+try {
+ var_dump(shr64(1));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(shr64(-1));
+} catch (Throwable $e) {
+ echo "Exception " . $e->getMessage() . "\n";
+}
+try {
+ var_dump(shrNEG(1));
+} catch (Throwable $e) {
+ echo "Exception (" . get_class($e) . "): " . $e->getMessage() . "\n";
+}
+?>
+--EXPECT--
+int(256)
+int(128)
+int(64)
+int(-2)
+int(0)
+int(-1)
+Exception (ArithmeticError): Bit shift by negative number
diff --git a/ext/opcache/tests/jit/shift_right_003.phpt b/ext/opcache/tests/jit/shift_right_003.phpt
new file mode 100644
index 0000000000..7fdf601d64
--- /dev/null
+++ b/ext/opcache/tests/jit/shift_right_003.phpt
@@ -0,0 +1,26 @@
+--TEST--
+JIT Shift Right: 003
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function encodeDynamicInteger(int $int): string {
+ $out = "";
+ for ($i = 0; ($int >> $i) > 0x80; $i += 7) {
+ $out .= \chr(0x80 | (($int >> $i) & 0x7f));
+ }
+ return $out . \chr($int >> $i);
+}
+$s = encodeDynamicInteger(235);
+var_dump(strlen($s), ord($s[0]), ord($s[1]));
+?>
+--EXPECT--
+int(2)
+int(235)
+int(1)
diff --git a/ext/opcache/tests/jit/skipif.inc b/ext/opcache/tests/jit/skipif.inc
new file mode 100644
index 0000000000..c5a8181039
--- /dev/null
+++ b/ext/opcache/tests/jit/skipif.inc
@@ -0,0 +1,3 @@
+<?php
+ if (!extension_loaded('Zend OPcache')) die('skip Zend OPcache extension not available');
+?>
diff --git a/ext/opcache/tests/jit/switch_jumptable.phpt b/ext/opcache/tests/jit/switch_jumptable.phpt
new file mode 100644
index 0000000000..df59a48c14
--- /dev/null
+++ b/ext/opcache/tests/jit/switch_jumptable.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Switch jumptable generation
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+function test1(string $val) {
+ switch ($val) {
+ case 'str1':
+ case 'str2':
+ echo "correct\n";
+ return;
+ }
+ echo "wrong\n";
+}
+function test2(int $val) {
+ switch ($val) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ echo "correct\n";
+ return;
+ }
+ echo "wrong\n";
+}
+test1("str1");
+test2(1);
+
+?>
+--EXPECT--
+correct
+correct
diff --git a/ext/opcache/tests/jit/type_check_001.phpt b/ext/opcache/tests/jit/type_check_001.phpt
new file mode 100644
index 0000000000..6573f0ebdc
--- /dev/null
+++ b/ext/opcache/tests/jit/type_check_001.phpt
@@ -0,0 +1,25 @@
+--TEST--
+JIT TYPE_CHECK: 001 exception handling
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+set_error_handler(function($no, $msg) {
+ throw new Exception($msg);
+});
+
+try {
+ if (!is_scalar($a)) {
+ undefined_function('Null');
+ }
+} catch (Exception $e) {
+ echo "Exception: " . $e->getMessage() . "\n";
+}
+?>
+--EXPECT--
+Exception: Undefined variable: a
diff --git a/ext/opcache/tests/jit/unreachable_block.phpt b/ext/opcache/tests/jit/unreachable_block.phpt
new file mode 100644
index 0000000000..cf60efaef3
--- /dev/null
+++ b/ext/opcache/tests/jit/unreachable_block.phpt
@@ -0,0 +1,25 @@
+--TEST--
+JIT unreachable_block with block order
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.file_update_protection=0
+opcache.jit_buffer_size=1M
+opcache.protect_memory=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class A {
+ public function Value()
+ {
+ switch ($this->returnType) {
+ case 'float': return $this->returnTypeNullable ? null : 0;
+ default: return;
+ }
+ }
+}
+?>
+okey
+--EXPECT--
+okey
diff --git a/ext/opcache/tests/jmpz_jmp_elim.phpt b/ext/opcache/tests/jmpz_jmp_elim.phpt
index 8a343512dd..434897bf80 100644
--- a/ext/opcache/tests/jmpz_jmp_elim.phpt
+++ b/ext/opcache/tests/jmpz_jmp_elim.phpt
@@ -14,5 +14,5 @@ echo "done\n";
?>
--EXPECTF--
-Notice: Undefined variable: undef in %s on line %d
+Warning: Undefined variable: undef in %s on line %d
done
diff --git a/ext/opcache/tests/opt/block_pass_001.phpt b/ext/opcache/tests/opt/block_pass_001.phpt
new file mode 100644
index 0000000000..788994ea4e
--- /dev/null
+++ b/ext/opcache/tests/opt/block_pass_001.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Block Pass 001: QM_ASSIGN and DECLARE_LAMBDA_FUNCTION
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+abstract class Broadcaster {
+ protected function normalizeChannelHandlerToCallable($callback)
+ {
+ return is_callable($callback) ? $callback : function (...$args) use ($callback) {
+ return Container::getInstance()
+ ->make($callback)
+ ->join(...$args);
+ };
+ }
+}
+?>
+OK
+--EXPECT--
+OK
diff --git a/ext/opcache/tests/opt/block_pass_002.phpt b/ext/opcache/tests/opt/block_pass_002.phpt
new file mode 100644
index 0000000000..38722ea49b
--- /dev/null
+++ b/ext/opcache/tests/opt/block_pass_002.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Block Pass 002: QM_ASSIGN and INIT_ARRAY
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo($key, $value, array $attributes) {
+ return is_array($value)
+ ? [$key, array_merge($value, $attributes)]
+ : [$value, $attributes];
+}
+?>
+OK
+--EXPECT--
+OK
diff --git a/ext/opcache/tests/opt/dce_001.phpt b/ext/opcache/tests/opt/dce_001.phpt
index 1afc3eba06..77a3da6809 100644
--- a/ext/opcache/tests/opt/dce_001.phpt
+++ b/ext/opcache/tests/opt/dce_001.phpt
@@ -11,9 +11,9 @@ opcache.preload=
--FILE--
<?php
function foo(string $s1, string $s2, string $s3, string $s4) {
- $x = ($s1 . $s2) . ($s3 . $s4);
- $x = 0;
- return $x;
+ $x = ($s1 . $s2) . ($s3 . $s4);
+ $x = 0;
+ return $x;
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/dce_002.phpt b/ext/opcache/tests/opt/dce_002.phpt
index fb1c070b35..002ada627d 100644
--- a/ext/opcache/tests/opt/dce_002.phpt
+++ b/ext/opcache/tests/opt/dce_002.phpt
@@ -11,12 +11,12 @@ opcache.preload=
--FILE--
<?php
function foo(int $a) {
- $a = 10;
- $b = 20;
- $x = func_get_args();
- $a = 30;
- $b = 40;
- return $x;
+ $a = 10;
+ $b = 20;
+ $x = func_get_args();
+ $a = 30;
+ $b = 40;
+ return $x;
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/dce_003.phpt b/ext/opcache/tests/opt/dce_003.phpt
index 0de39c042c..a60e982b95 100644
--- a/ext/opcache/tests/opt/dce_003.phpt
+++ b/ext/opcache/tests/opt/dce_003.phpt
@@ -11,8 +11,8 @@ opcache.preload=
--FILE--
<?php
function foo(int $a) {
- $b = $a += 3;
- return $a;
+ $b = $a += 3;
+ return $a;
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/dce_004.phpt b/ext/opcache/tests/opt/dce_004.phpt
index 90bfc52d97..d595c17acb 100644
--- a/ext/opcache/tests/opt/dce_004.phpt
+++ b/ext/opcache/tests/opt/dce_004.phpt
@@ -11,10 +11,10 @@ opcache.preload=
--FILE--
<?php
function foo(int $x, int $y) {
- $a = [$x];
- $a[1] = $y;
- $a = $y;
- return $a;
+ $a = [$x];
+ $a[1] = $y;
+ $a = $y;
+ return $a;
}
--EXPECTF--
$_main: ; (lines=1, args=0, vars=0, tmps=0)
diff --git a/ext/opcache/tests/opt/dce_005.phpt b/ext/opcache/tests/opt/dce_005.phpt
index 3888ccd53f..294cf92b33 100644
--- a/ext/opcache/tests/opt/dce_005.phpt
+++ b/ext/opcache/tests/opt/dce_005.phpt
@@ -13,8 +13,8 @@ opcache.preload=
class A {
}
function foo(int $x) {
- $a = new A;
- $a->foo = $x;
+ $a = new A;
+ $a->foo = $x;
}
--EXPECTF--
$_main: ; (lines=1, args=0, vars=0, tmps=0)
diff --git a/ext/opcache/tests/opt/dce_006.phpt b/ext/opcache/tests/opt/dce_006.phpt
index c84805247a..c595f9088d 100644
--- a/ext/opcache/tests/opt/dce_006.phpt
+++ b/ext/opcache/tests/opt/dce_006.phpt
@@ -11,11 +11,11 @@ opcache.preload=
--FILE--
<?php
class A {
- function __destruct() {}
+ function __destruct() {}
}
function foo(int $x) {
- $a = new A;
- $a->foo = $x;
+ $a = new A;
+ $a->foo = $x;
}
--EXPECTF--
$_main: ; (lines=1, args=0, vars=0, tmps=0)
diff --git a/ext/opcache/tests/opt/sccp_001.phpt b/ext/opcache/tests/opt/sccp_001.phpt
index 1f67f985e3..d7cb8c700a 100644
--- a/ext/opcache/tests/opt/sccp_001.phpt
+++ b/ext/opcache/tests/opt/sccp_001.phpt
@@ -11,10 +11,10 @@ opcache.preload=
--FILE--
<?php
function foo() {
- $a = 1;
- $b = $a + 2;
- $a += $b;
- return $a;
+ $a = 1;
+ $b = $a + 2;
+ $a += $b;
+ return $a;
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/sccp_002.phpt b/ext/opcache/tests/opt/sccp_002.phpt
index 0fd10f2ac5..ff00281a03 100644
--- a/ext/opcache/tests/opt/sccp_002.phpt
+++ b/ext/opcache/tests/opt/sccp_002.phpt
@@ -11,15 +11,15 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a = [$x];
- $i = 1;
- $c = $i < 2;
- if ($c) {
- $k = 2 * $i;
- $a[$k] = $i;
- echo $a[$k];
- }
- echo $a[2];
+ $a = [$x];
+ $i = 1;
+ $c = $i < 2;
+ if ($c) {
+ $k = 2 * $i;
+ $a[$k] = $i;
+ echo $a[$k];
+ }
+ echo $a[2];
}
?>
--EXPECTF--
@@ -32,6 +32,6 @@ foo: ; (lines=4, args=1, vars=1, tmps=0)
; (after optimizer)
; %ssccp_002.php:2-12
L0 (2): CV0($x) = RECV 1
-L1 (9): ECHO int(1)
-L2 (11): ECHO int(1)
+L1 (9): ECHO string("1")
+L2 (11): ECHO string("1")
L3 (12): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_003.phpt b/ext/opcache/tests/opt/sccp_003.phpt
index 282a5788e6..a0ac2e0236 100644
--- a/ext/opcache/tests/opt/sccp_003.phpt
+++ b/ext/opcache/tests/opt/sccp_003.phpt
@@ -11,15 +11,15 @@ opcache.preload=
--FILE--
<?php
function foo() {
- $a = [1,2,3];
- $i = 1;
- $c = $i < 2;
- if ($c) {
- $k = 2 * $i;
- $a[$k] = $i;
- echo $a[$k];
- }
- echo $a[2];
+ $a = [1,2,3];
+ $i = 1;
+ $c = $i < 2;
+ if ($c) {
+ $k = 2 * $i;
+ $a[$k] = $i;
+ echo $a[$k];
+ }
+ echo $a[2];
}
?>
--EXPECTF--
@@ -31,6 +31,6 @@ L0 (14): RETURN int(1)
foo: ; (lines=3, args=0, vars=0, tmps=0)
; (after optimizer)
; %ssccp_003.php:2-12
-L0 (9): ECHO int(1)
-L1 (11): ECHO int(1)
+L0 (9): ECHO string("1")
+L1 (11): ECHO string("1")
L2 (12): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_004.phpt b/ext/opcache/tests/opt/sccp_004.phpt
index d82212e0ef..659e3488c1 100644
--- a/ext/opcache/tests/opt/sccp_004.phpt
+++ b/ext/opcache/tests/opt/sccp_004.phpt
@@ -11,18 +11,18 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a = [1,2,3];
- $a[2] = $x;
- $i = 1;
- $c = $i < 2;
- if ($c) {
- $k = 2 * $i;
- $a[$k] = $i;
+ $a = [1,2,3];
+ $a[2] = $x;
+ $i = 1;
+ $c = $i < 2;
+ if ($c) {
+ $k = 2 * $i;
+ $a[$k] = $i;
// $a[$k]++;
- echo isset($a[$k]);
+ echo isset($a[$k]);
// $a[$k] += 5;
- }
- echo $a[2];
+ }
+ echo $a[2];
}
?>
--EXPECTF--
@@ -35,6 +35,6 @@ foo: ; (lines=4, args=1, vars=1, tmps=0)
; (after optimizer)
; %ssccp_004.php:2-15
L0 (2): CV0($x) = RECV 1
-L1 (11): ECHO bool(true)
-L2 (14): ECHO int(1)
+L1 (11): ECHO string("1")
+L2 (14): ECHO string("1")
L3 (15): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_005.phpt b/ext/opcache/tests/opt/sccp_005.phpt
index 7fbb062922..4fb86eacc0 100644
--- a/ext/opcache/tests/opt/sccp_005.phpt
+++ b/ext/opcache/tests/opt/sccp_005.phpt
@@ -11,8 +11,8 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a = [1,2,$x];
- echo $a[1];
+ $a = [1,2,$x];
+ echo $a[1];
}
?>
--EXPECTF--
@@ -25,5 +25,5 @@ foo: ; (lines=3, args=1, vars=1, tmps=0)
; (after optimizer)
; %ssccp_005.php:2-5
L0 (2): CV0($x) = RECV 1
-L1 (4): ECHO int(2)
+L1 (4): ECHO string("2")
L2 (5): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_006.phpt b/ext/opcache/tests/opt/sccp_006.phpt
index 60fa5f2f01..bc24ebbfb2 100644
--- a/ext/opcache/tests/opt/sccp_006.phpt
+++ b/ext/opcache/tests/opt/sccp_006.phpt
@@ -11,8 +11,8 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a = ["a"=>1,"a"=>2,"a"=>$x];
- echo $a["a"];
+ $a = ["a"=>1,"a"=>2,"a"=>$x];
+ echo $a["a"];
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/sccp_007.phpt b/ext/opcache/tests/opt/sccp_007.phpt
index 82feb04e22..44ff01e640 100644
--- a/ext/opcache/tests/opt/sccp_007.phpt
+++ b/ext/opcache/tests/opt/sccp_007.phpt
@@ -11,12 +11,12 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- if ($x) {
- $a = [0,1];
- } else {
- $a = [0,2];
- }
- echo $a[0];
+ if ($x) {
+ $a = [0,1];
+ } else {
+ $a = [0,2];
+ }
+ echo $a[0];
}
?>
--EXPECTF--
@@ -29,5 +29,5 @@ foo: ; (lines=3, args=1, vars=1, tmps=0)
; (after optimizer)
; %ssccp_007.php:2-9
L0 (2): CV0($x) = RECV 1
-L1 (8): ECHO int(0)
+L1 (8): ECHO string("0")
L2 (9): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_008.phpt b/ext/opcache/tests/opt/sccp_008.phpt
index d652964a66..a5ba8a7d22 100644
--- a/ext/opcache/tests/opt/sccp_008.phpt
+++ b/ext/opcache/tests/opt/sccp_008.phpt
@@ -11,12 +11,12 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- if ($x) {
- $a = [0,1];
- } else {
- $a = [0,2];
- }
- echo $a[1];
+ if ($x) {
+ $a = [0,1];
+ } else {
+ $a = [0,2];
+ }
+ echo $a[1];
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/sccp_009.phpt b/ext/opcache/tests/opt/sccp_009.phpt
index 1b049810c1..601586fd64 100644
--- a/ext/opcache/tests/opt/sccp_009.phpt
+++ b/ext/opcache/tests/opt/sccp_009.phpt
@@ -11,9 +11,9 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a[0] = $x;
- $a[1] = 2;
- echo $a[1];
+ $a[0] = $x;
+ $a[1] = 2;
+ echo $a[1];
}
?>
--EXPECTF--
@@ -26,5 +26,5 @@ foo: ; (lines=3, args=1, vars=1, tmps=0)
; (after optimizer)
; %ssccp_009.php:2-6
L0 (2): CV0($x) = RECV 1
-L1 (5): ECHO int(2)
+L1 (5): ECHO string("2")
L2 (6): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_010.phpt b/ext/opcache/tests/opt/sccp_010.phpt
index e88bf579f7..8943b179e3 100644
--- a/ext/opcache/tests/opt/sccp_010.phpt
+++ b/ext/opcache/tests/opt/sccp_010.phpt
@@ -13,14 +13,14 @@ opcache.preload=
function foo() {
$o = new stdClass();
$o->foo = 0;
- $i = 1;
- $c = $i < 2;
- if ($c) {
- $k = 2 * $i;
- $o->foo = $i;
- echo $o->foo;
- }
- echo $o->foo;
+ $i = 1;
+ $c = $i < 2;
+ if ($c) {
+ $k = 2 * $i;
+ $o->foo = $i;
+ echo $o->foo;
+ }
+ echo $o->foo;
}
?>
--EXPECTF--
@@ -32,6 +32,6 @@ L0 (15): RETURN int(1)
foo: ; (lines=3, args=0, vars=0, tmps=0)
; (after optimizer)
; %ssccp_010.php:2-13
-L0 (10): ECHO int(1)
-L1 (12): ECHO int(1)
+L0 (10): ECHO string("1")
+L1 (12): ECHO string("1")
L2 (13): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_011.phpt b/ext/opcache/tests/opt/sccp_011.phpt
index 281e3dca2e..4bd90b18e6 100644
--- a/ext/opcache/tests/opt/sccp_011.phpt
+++ b/ext/opcache/tests/opt/sccp_011.phpt
@@ -11,15 +11,15 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $o = new stdClass;
- if ($x) {
- $o->foo = 0;
- $o->bar = 1;
- } else {
- $o->foo = 0;
- $o->bar = 2;
- }
- echo $o->foo;
+ $o = new stdClass;
+ if ($x) {
+ $o->foo = 0;
+ $o->bar = 1;
+ } else {
+ $o->foo = 0;
+ $o->bar = 2;
+ }
+ echo $o->foo;
}
?>
--EXPECTF--
@@ -32,5 +32,5 @@ foo: ; (lines=3, args=1, vars=1, tmps=0)
; (after optimizer)
; %ssccp_011.php:2-12
L0 (2): CV0($x) = RECV 1
-L1 (11): ECHO int(0)
+L1 (11): ECHO string("0")
L2 (12): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_012.phpt b/ext/opcache/tests/opt/sccp_012.phpt
index 5d2f3e9a01..1ad1ed3b4c 100644
--- a/ext/opcache/tests/opt/sccp_012.phpt
+++ b/ext/opcache/tests/opt/sccp_012.phpt
@@ -13,16 +13,16 @@ opcache.preload=
function foo() {
$o = new stdClass();
$o->foo = 0;
- $i = 1;
- $c = $i < 2;
- if ($c) {
- $k = 2 * $i;
- $o->foo = $i;
- echo $o->foo;
- }
- $o->foo += 2;
- $o->foo++;
- echo $o->foo;
+ $i = 1;
+ $c = $i < 2;
+ if ($c) {
+ $k = 2 * $i;
+ $o->foo = $i;
+ echo $o->foo;
+ }
+ $o->foo += 2;
+ $o->foo++;
+ echo $o->foo;
}
?>
--EXPECTF--
@@ -34,6 +34,6 @@ L0 (17): RETURN int(1)
foo: ; (lines=3, args=0, vars=0, tmps=0)
; (after optimizer)
; %ssccp_012.php:2-15
-L0 (10): ECHO int(1)
-L1 (14): ECHO int(4)
+L0 (10): ECHO string("1")
+L1 (14): ECHO string("4")
L2 (15): RETURN null
diff --git a/ext/opcache/tests/opt/sccp_013.phpt b/ext/opcache/tests/opt/sccp_013.phpt
index 18b57a4185..1ed9c7703b 100644
--- a/ext/opcache/tests/opt/sccp_013.phpt
+++ b/ext/opcache/tests/opt/sccp_013.phpt
@@ -9,11 +9,11 @@ opcache.optimization_level=-1
--FILE--
<?php
function loadEntities($entity_information) {
- $entity_types = [];
- foreach ($entity_information as $info) {
- $entity_types[$info] = 1;
- }
- var_dump((bool)($entity_types[$info]));
+ $entity_types = [];
+ foreach ($entity_information as $info) {
+ $entity_types[$info] = 1;
+ }
+ var_dump((bool)($entity_types[$info]));
}
loadEntities(array("first", "second"));
diff --git a/ext/opcache/tests/opt/sccp_014.phpt b/ext/opcache/tests/opt/sccp_014.phpt
index 2898239e7c..81f21a4ab0 100644
--- a/ext/opcache/tests/opt/sccp_014.phpt
+++ b/ext/opcache/tests/opt/sccp_014.phpt
@@ -9,12 +9,12 @@ opcache.optimization_level=-1
--FILE--
<?php
function loadEntities($entity_information) {
- $entity_types = new StdClass();
- $entity_types->a = 1;
- foreach ($entity_information as $info) {
- $entity_types->a = 0;
- }
- var_dump((bool)($entity_types->a));
+ $entity_types = new StdClass();
+ $entity_types->a = 1;
+ foreach ($entity_information as $info) {
+ $entity_types->a = 0;
+ }
+ var_dump((bool)($entity_types->a));
}
loadEntities(array("first", "second"));
diff --git a/ext/opcache/tests/opt/sccp_015.phpt b/ext/opcache/tests/opt/sccp_015.phpt
index b31f4edc15..d11bd6c9e0 100644
--- a/ext/opcache/tests/opt/sccp_015.phpt
+++ b/ext/opcache/tests/opt/sccp_015.phpt
@@ -9,14 +9,14 @@ opcache.optimization_level=-1
--FILE--
<?php
function loadEntities($entity_information) {
- $entity_types = new StdClass();
- $entity_types->b = 0;
- foreach ($entity_information as $ex) {
- var_dump((bool)$entity_types->b);
- foreach ($entity_information as $info) {
- $entity_types->b = 1;
- }
- }
+ $entity_types = new StdClass();
+ $entity_types->b = 0;
+ foreach ($entity_information as $ex) {
+ var_dump((bool)$entity_types->b);
+ foreach ($entity_information as $info) {
+ $entity_types->b = 1;
+ }
+ }
}
loadEntities(array("first", "second"));
diff --git a/ext/opcache/tests/opt/sccp_017.phpt b/ext/opcache/tests/opt/sccp_017.phpt
index c2bc6f35fb..e72d892bdc 100644
--- a/ext/opcache/tests/opt/sccp_017.phpt
+++ b/ext/opcache/tests/opt/sccp_017.phpt
@@ -1,5 +1,5 @@
--TEST--
-SCCP 017: Array assignemnt
+SCCP 017: Array assignment
--INI--
opcache.enable=1
opcache.enable_cli=1
@@ -11,11 +11,11 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a[0] = 5;
- $a[1] = $x;
- $b = $a;
- $b[0] = 42;
- return $a[0];
+ $a[0] = 5;
+ $a[1] = $x;
+ $b = $a;
+ $b[0] = 42;
+ return $a[0];
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/sccp_018.phpt b/ext/opcache/tests/opt/sccp_018.phpt
index 66a4b6ca15..e7a78ef50d 100644
--- a/ext/opcache/tests/opt/sccp_018.phpt
+++ b/ext/opcache/tests/opt/sccp_018.phpt
@@ -1,5 +1,5 @@
--TEST--
-SCCP 018: Object assignemnt
+SCCP 018: Object assignment
--INI--
opcache.enable=1
opcache.enable_cli=1
@@ -10,12 +10,12 @@ opcache.optimization_level=-1
--FILE--
<?php
function foo() {
- $a = new stdClass;
- $b = $a;
- $a->x = 5;
- $b->x = 42;
- echo $a->x;
- echo "\n";
+ $a = new stdClass;
+ $b = $a;
+ $a->x = 5;
+ $b->x = 42;
+ echo $a->x;
+ echo "\n";
}
foo();
?>
diff --git a/ext/opcache/tests/opt/sccp_019.phpt b/ext/opcache/tests/opt/sccp_019.phpt
index 5a32bd2205..3ed2d6bd81 100644
--- a/ext/opcache/tests/opt/sccp_019.phpt
+++ b/ext/opcache/tests/opt/sccp_019.phpt
@@ -1,5 +1,5 @@
--TEST--
-SCCP 019: Array assignemnt
+SCCP 019: Array assignment
--INI--
opcache.enable=1
opcache.enable_cli=1
@@ -11,10 +11,10 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a[0] = 5;
- $a[1] = $x;
- $b = $a;
- return $b[0];
+ $a[0] = 5;
+ $a[1] = $x;
+ $b = $a;
+ return $b[0];
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/sccp_020.phpt b/ext/opcache/tests/opt/sccp_020.phpt
index 41c694a591..be972f4fdf 100644
--- a/ext/opcache/tests/opt/sccp_020.phpt
+++ b/ext/opcache/tests/opt/sccp_020.phpt
@@ -1,5 +1,5 @@
--TEST--
-SCCP 020: Object assignemnt
+SCCP 020: Object assignment
--INI--
opcache.enable=1
opcache.enable_cli=1
@@ -10,11 +10,11 @@ opcache.optimization_level=-1
--FILE--
<?php
function foo() {
- $b = $a = new stdClass;
- $a->x = 5;
- $b->x = 42;
- echo $a->x;
- echo "\n";
+ $b = $a = new stdClass;
+ $a->x = 5;
+ $b->x = 42;
+ echo $a->x;
+ echo "\n";
}
foo();
?>
diff --git a/ext/opcache/tests/opt/sccp_021.phpt b/ext/opcache/tests/opt/sccp_021.phpt
index 327cbc9a91..1eb8de4516 100644
--- a/ext/opcache/tests/opt/sccp_021.phpt
+++ b/ext/opcache/tests/opt/sccp_021.phpt
@@ -10,19 +10,19 @@ opcache.optimization_level=-1
--FILE--
<?php
class A {
- public function memleak($num_tokens) {
- $queries = array();
- for ( $i = 0; $i < $num_tokens; ++$i ) {
- if ( 0 < $i )
- $queries[$i] = $queries[$i - 1] . '&';
- else
- $queries[$i] = '';
+ public function memleak($num_tokens) {
+ $queries = array();
+ for ( $i = 0; $i < $num_tokens; ++$i ) {
+ if ( 0 < $i )
+ $queries[$i] = $queries[$i - 1] . '&';
+ else
+ $queries[$i] = '';
- $queries[$i] .= $query_token;
- }
+ $queries[$i] .= $query_token;
+ }
- return;
- }
+ return;
+ }
}
?>
okey
diff --git a/ext/opcache/tests/opt/sccp_022.phpt b/ext/opcache/tests/opt/sccp_022.phpt
index 03a8d565f2..000b1ab8b3 100644
--- a/ext/opcache/tests/opt/sccp_022.phpt
+++ b/ext/opcache/tests/opt/sccp_022.phpt
@@ -1,5 +1,5 @@
--TEST--
-SCCP 022: Invailid types
+SCCP 022: Invalid types
--INI--
opcache.enable=1
opcache.enable_cli=1
@@ -11,11 +11,11 @@ opcache.preload=
--FILE--
<?php
function foo(int $x) {
- $a[0] = $x;
- $a[1] = 5;
- echo $a[1];
- $a->foo = 5;
- echo $a[1];
+ $a[0] = $x;
+ $a[1] = 5;
+ echo $a[1];
+ $a->foo = 5;
+ echo $a[1];
}
?>
--EXPECTF--
@@ -32,7 +32,7 @@ L1 (3): ASSIGN_DIM CV1($a) int(0)
L2 (3): OP_DATA CV0($x)
L3 (4): ASSIGN_DIM CV1($a) int(1)
L4 (4): OP_DATA int(5)
-L5 (5): ECHO int(5)
+L5 (5): ECHO string("5")
L6 (6): ASSIGN_OBJ CV1($a) string("foo")
L7 (6): OP_DATA int(5)
L8 (7): T2 = FETCH_DIM_R CV1($a) int(1)
diff --git a/ext/opcache/tests/opt/sccp_023.phpt b/ext/opcache/tests/opt/sccp_023.phpt
index d327d6279e..efa7d6b013 100644
--- a/ext/opcache/tests/opt/sccp_023.phpt
+++ b/ext/opcache/tests/opt/sccp_023.phpt
@@ -10,13 +10,13 @@ opcache.opt_debug_level=0
--FILE--
<?php
function a ($field_type, $allowed_values) {
- $settings = [
- 'list_string' => [
- 'allowed_values' => $allowed_values,
- ],
- ];
+ $settings = [
+ 'list_string' => [
+ 'allowed_values' => $allowed_values,
+ ],
+ ];
- return $settings[$field_type];
+ return $settings[$field_type];
}
var_dump(a("list_string", ["xxx"]));
diff --git a/ext/opcache/tests/opt/sccp_024.phpt b/ext/opcache/tests/opt/sccp_024.phpt
index e6e2e311ef..bd9a2fed67 100644
--- a/ext/opcache/tests/opt/sccp_024.phpt
+++ b/ext/opcache/tests/opt/sccp_024.phpt
@@ -11,14 +11,14 @@ opcache.preload=
--FILE--
<?php
class A {
- function t($obj) {
- $a = "A";
+ function t($obj) {
+ $a = "A";
$b = "self";
$c = 1;
echo ($obj instanceof $a);
echo ($obj instanceof $b);
echo ($obj instanceof $c);
- }
+ }
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/sccp_025.phpt b/ext/opcache/tests/opt/sccp_025.phpt
index 8f46dab830..f78e8822d7 100644
--- a/ext/opcache/tests/opt/sccp_025.phpt
+++ b/ext/opcache/tests/opt/sccp_025.phpt
@@ -11,31 +11,31 @@ opcache.opt_debug_level=0
<?php
function test($phpEx)
{
- $expected_data_sets = array(
- 1 => array(
- 'id' => 1,
- ),
- 6 => array(
- 'viewtopic' => strval("phpBB/viewtopic.$phpEx"),
+ $expected_data_sets = array(
+ 1 => array(
+ 'id' => 1,
+ ),
+ 6 => array(
+ 'viewtopic' => strval("phpBB/viewtopic.$phpEx"),
- ),
- );
+ ),
+ );
- $test_cases = array(
- array(
- 'expected' => array(6),
- ),
- );
+ $test_cases = array(
+ array(
+ 'expected' => array(6),
+ ),
+ );
- foreach ($test_cases as $case => $case_data)
- {
- foreach ($case_data['expected'] as $data_set => $expected)
- {
- $test_cases[$case]['expected'][$data_set] = $expected_data_sets[$expected];
- }
- }
+ foreach ($test_cases as $case => $case_data)
+ {
+ foreach ($case_data['expected'] as $data_set => $expected)
+ {
+ $test_cases[$case]['expected'][$data_set] = $expected_data_sets[$expected];
+ }
+ }
- return $test_cases;
+ return $test_cases;
}
var_dump(test("xxx"));
?>
diff --git a/ext/opcache/tests/opt/sccp_026.phpt b/ext/opcache/tests/opt/sccp_026.phpt
index 132c9ddef3..6f02a57a5a 100644
--- a/ext/opcache/tests/opt/sccp_026.phpt
+++ b/ext/opcache/tests/opt/sccp_026.phpt
@@ -15,7 +15,7 @@ function test($var) {
return;
}
- var_dump($username);
+ var_dump($username);
}
?>
--EXPECTF--
diff --git a/ext/opcache/tests/opt/sccp_027.phpt b/ext/opcache/tests/opt/sccp_027.phpt
index 38189592b0..5c13111d1c 100644
--- a/ext/opcache/tests/opt/sccp_027.phpt
+++ b/ext/opcache/tests/opt/sccp_027.phpt
@@ -10,15 +10,15 @@ opcache.preload=
--FILE--
<?php
class Foo {
- protected $arr;
- public function init($a) {
- $this->arr =& $a;
- if (isset($a[0])) {
- return 1;
- } else {
- return 2;
- }
- }
+ protected $arr;
+ public function init($a) {
+ $this->arr =& $a;
+ if (isset($a[0])) {
+ return 1;
+ } else {
+ return 2;
+ }
+ }
}
$x = new Foo();
var_dump($x->init([1]));
diff --git a/ext/opcache/tests/opt/sccp_029.phpt b/ext/opcache/tests/opt/sccp_029.phpt
index 3a16477711..99459f74af 100644
--- a/ext/opcache/tests/opt/sccp_029.phpt
+++ b/ext/opcache/tests/opt/sccp_029.phpt
@@ -10,7 +10,7 @@ opcache.preload=
--FILE--
<?php
-class Test {
+class Test {
public string $x = "x";
}
function test() {
diff --git a/ext/opcache/tests/opt/sccp_031.phpt b/ext/opcache/tests/opt/sccp_031.phpt
new file mode 100644
index 0000000000..b787e7c979
--- /dev/null
+++ b/ext/opcache/tests/opt/sccp_031.phpt
@@ -0,0 +1,36 @@
+--TEST--
+SCCP 031: Echo optimizations
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.opt_debug_level=0x20000
+opcache.preload=
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo() {
+ $k = 0;
+ $a = [null];
+ echo isset($a[$k]);
+ echo "b";
+ echo isset($a[$k+1]);
+ echo "c";
+ echo $a[$k];
+ echo $a; // Should not be optimized
+}
+?>
+--EXPECTF--
+$_main: ; (lines=1, args=0, vars=0, tmps=0)
+ ; (after optimizer)
+ ; %ssccp_031.php:1-13
+L0 (13): RETURN int(1)
+
+foo: ; (lines=4, args=0, vars=0, tmps=0)
+ ; (after optimizer)
+ ; %s_031.php:2-11
+L0 (6): ECHO string("b")
+L1 (8): ECHO string("c")
+L2 (10): ECHO array(...)
+L3 (11): RETURN null
diff --git a/ext/opcache/tests/optimize_func_calls.phpt b/ext/opcache/tests/optimize_func_calls.phpt
index eb1a6b38b4..3e2a8dd8f4 100644
--- a/ext/opcache/tests/optimize_func_calls.phpt
+++ b/ext/opcache/tests/optimize_func_calls.phpt
@@ -10,14 +10,14 @@ opcache.optimization_level=-1
<?php
class A {
- public $obj;
- public function test($a) {
- }
+ public $obj;
+ public function test($a) {
+ }
}
function a(&$b) {
- $b = "changed";
- return "done";
+ $b = "changed";
+ return "done";
}
$a = "a";
@@ -78,16 +78,16 @@ var_dump($b);
ref("xxx");
function retarray() {
- return array("retarray");
+ return array("retarray");
}
function foo($a) {
- print_r(func_get_args());
+ print_r(func_get_args());
}
function ref(&$b) {
- $b = "changed";
- return "ref";
+ $b = "changed";
+ return "ref";
}
--EXPECTF--
Array
diff --git a/ext/opcache/tests/optimize_static_001.phpt b/ext/opcache/tests/optimize_static_001.phpt
index d4e2c58062..aac2d71907 100644
--- a/ext/opcache/tests/optimize_static_001.phpt
+++ b/ext/opcache/tests/optimize_static_001.phpt
@@ -9,11 +9,15 @@ opcache.optimization_level=-1
--FILE--
<?php
function foo() {
- static $a = UNDEFINED_CONST;
+ static $a = UNDEFINED_CONST;
+}
+try {
+ foo();
+} catch (Throwable $e) {
+ echo "Exception: " . $e->getMessage() . "\n";
}
-foo();
?>
OK
---EXPECTF--
-Warning: Use of undefined constant UNDEFINED_CONST - assumed 'UNDEFINED_CONST' (this will throw an Error in a future version of PHP) in %s on line %d
+--EXPECT--
+Exception: Undefined constant 'UNDEFINED_CONST'
OK \ No newline at end of file
diff --git a/ext/opcache/tests/phi_remove_001.phpt b/ext/opcache/tests/phi_remove_001.phpt
index 3a76a9da5c..d8c1a64eec 100644
--- a/ext/opcache/tests/phi_remove_001.phpt
+++ b/ext/opcache/tests/phi_remove_001.phpt
@@ -9,58 +9,58 @@ opcache.optimization_level=-1
--FILE--
<?php
function getOnlyMPEGaudioInfoBruteForce($info) {
- $Distribution['bitrate'] = array();
- $Distribution['frequency'] = array();
- $Distribution['layer'] = array();
- $Distribution['version'] = array();
- $Distribution['padding'] = array();
+ $Distribution['bitrate'] = array();
+ $Distribution['frequency'] = array();
+ $Distribution['layer'] = array();
+ $Distribution['version'] = array();
+ $Distribution['padding'] = array();
- $max_frames_scan = 5000;
- $frames_scanned = 0;
+ $max_frames_scan = 5000;
+ $frames_scanned = 0;
- $previousvalidframe = $info['avdataoffset'];
- while ($info) {
- if (!isset($MPEGaudioHeaderDecodeCache[$head4])) {
- $MPEGaudioHeaderDecodeCache[$head4] = MPEGaudioHeaderDecode($head4);
- }
- if (!isset($MPEGaudioHeaderValidCache[$head4])) {
- $MPEGaudioHeaderValidCache[$head4] = MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false);
- }
- if ($MPEGaudioHeaderValidCache[$head4]) {
+ $previousvalidframe = $info['avdataoffset'];
+ while ($info) {
+ if (!isset($MPEGaudioHeaderDecodeCache[$head4])) {
+ $MPEGaudioHeaderDecodeCache[$head4] = MPEGaudioHeaderDecode($head4);
+ }
+ if (!isset($MPEGaudioHeaderValidCache[$head4])) {
+ $MPEGaudioHeaderValidCache[$head4] = MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false);
+ }
+ if ($MPEGaudioHeaderValidCache[$head4]) {
- if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
- $WhereWeWere = mftell();
- $next4 = test(4);
- if ($next4[0] == "\xFF") {
- if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
- $MPEGaudioHeaderDecodeCache[$next4] = MPEGaudioHeaderDecode($next4);
- }
- if (!isset($MPEGaudioHeaderValidCache[$next4])) {
- $MPEGaudioHeaderValidCache[$next4] = MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
- }
- if ($MPEGaudioHeaderValidCache[$next4]) {
- getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
- getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
- getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
- getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
- getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
- if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
- foreach ($Distribution as $key1 => $value1) {
- foreach ($value1 as $key2 => $value2) {
- $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
- }
- }
- break;
- }
- continue;
- }
- }
- unset($next4);
- }
+ if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
+ $WhereWeWere = mftell();
+ $next4 = test(4);
+ if ($next4[0] == "\xFF") {
+ if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
+ $MPEGaudioHeaderDecodeCache[$next4] = MPEGaudioHeaderDecode($next4);
+ }
+ if (!isset($MPEGaudioHeaderValidCache[$next4])) {
+ $MPEGaudioHeaderValidCache[$next4] = MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
+ }
+ if ($MPEGaudioHeaderValidCache[$next4]) {
+ getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
+ getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
+ if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
+ foreach ($Distribution as $key1 => $value1) {
+ foreach ($value1 as $key2 => $value2) {
+ $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
+ }
+ }
+ break;
+ }
+ continue;
+ }
+ }
+ unset($next4);
+ }
- }
- }
- return true;
+ }
+ }
+ return true;
}
?>
okey
diff --git a/ext/opcache/tests/phi_remove_002.phpt b/ext/opcache/tests/phi_remove_002.phpt
index 3b0c429d50..7e8b64bdf3 100644
--- a/ext/opcache/tests/phi_remove_002.phpt
+++ b/ext/opcache/tests/phi_remove_002.phpt
@@ -9,13 +9,13 @@ opcache.optimization_level=-1
--FILE--
<?php
function func($blogname, $user = '' ) {
- if (! is_object( $user ) || ( is_object($user) && ( $user->login != $blogname )) ) {
- test();
- }
+ if (! is_object( $user ) || ( is_object($user) && ( $user->login != $blogname )) ) {
+ test();
+ }
- $result = array('user' => $user);
+ $result = array('user' => $user);
- return true;
+ return true;
}
?>
okey
diff --git a/ext/opcache/tests/php_cli_server.inc b/ext/opcache/tests/php_cli_server.inc
index e32cf9f97f..8d15b81c79 100644
--- a/ext/opcache/tests/php_cli_server.inc
+++ b/ext/opcache/tests/php_cli_server.inc
@@ -4,64 +4,64 @@ define ("PHP_CLI_SERVER_PORT", 8964);
define ("PHP_CLI_SERVER_ADDRESS", PHP_CLI_SERVER_HOSTNAME.":".PHP_CLI_SERVER_PORT);
function php_cli_server_start($ini = "") {
- $php_executable = getenv('TEST_PHP_EXECUTABLE');
- $doc_root = __DIR__;
+ $php_executable = getenv('TEST_PHP_EXECUTABLE');
+ $doc_root = __DIR__;
- $ini_array = preg_split('/\s+/', trim($ini));
- $ini_array = array_map(function($arg) {
- return trim($arg, '\'"');
- }, $ini_array);
- $cmd = [$php_executable, '-t', $doc_root, '-n', ...$ini_array, '-S', PHP_CLI_SERVER_ADDRESS];
- $descriptorspec = array(
- 0 => STDIN,
- 1 => STDOUT,
- 2 => array("null"),
- );
- $handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root, null, array("suppress_errors" => true));
+ $ini_array = preg_split('/\s+/', trim($ini));
+ $ini_array = array_map(function($arg) {
+ return trim($arg, '\'"');
+ }, $ini_array);
+ $cmd = [$php_executable, '-t', $doc_root, '-n', ...$ini_array, '-S', PHP_CLI_SERVER_ADDRESS];
+ $descriptorspec = array(
+ 0 => STDIN,
+ 1 => STDOUT,
+ 2 => array("null"),
+ );
+ $handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root, null, array("suppress_errors" => true));
- // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
- // it might not be listening yet...need to wait until fsockopen() call returns
- $error = "Unable to connect to server\n";
- for ($i=0; $i < 60; $i++) {
- usleep(50000); // 50ms per try
- $status = proc_get_status($handle);
- $fp = @fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT);
- // Failure, the server is no longer running
- if (!($status && $status['running'])) {
- $error = "Server is not running\n";
- break;
- }
- // Success, Connected to servers
- if ($fp) {
- $error = '';
- break;
- }
- }
+ // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
+ // it might not be listening yet...need to wait until fsockopen() call returns
+ $error = "Unable to connect to server\n";
+ for ($i=0; $i < 60; $i++) {
+ usleep(50000); // 50ms per try
+ $status = proc_get_status($handle);
+ $fp = @fsockopen(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT);
+ // Failure, the server is no longer running
+ if (!($status && $status['running'])) {
+ $error = "Server is not running\n";
+ break;
+ }
+ // Success, Connected to servers
+ if ($fp) {
+ $error = '';
+ break;
+ }
+ }
- if ($fp) {
- fclose($fp);
- }
+ if ($fp) {
+ fclose($fp);
+ }
- if ($error) {
- echo $error;
- proc_terminate($handle);
- exit(1);
- }
+ if ($error) {
+ echo $error;
+ proc_terminate($handle);
+ exit(1);
+ }
- register_shutdown_function(
- function($handle) {
- proc_terminate($handle);
- /* Wait for server to shutdown */
- for ($i = 0; $i < 60; $i++) {
- $status = proc_get_status($handle);
- if (!($status && $status['running'])) {
- break;
- }
- usleep(50000);
- }
- },
- $handle
- );
+ register_shutdown_function(
+ function($handle) {
+ proc_terminate($handle);
+ /* Wait for server to shutdown */
+ for ($i = 0; $i < 60; $i++) {
+ $status = proc_get_status($handle);
+ if (!($status && $status['running'])) {
+ break;
+ }
+ usleep(50000);
+ }
+ },
+ $handle
+ );
}
?>
diff --git a/ext/opcache/tests/preload.inc b/ext/opcache/tests/preload.inc
index 10de9390d0..52bb60e348 100644
--- a/ext/opcache/tests/preload.inc
+++ b/ext/opcache/tests/preload.inc
@@ -3,39 +3,39 @@ function f1() {
}
if (isset($rt)) {
- function f2() {
- }
+ function f2() {
+ }
}
interface a {
- function foo();
- function bar();
+ function foo();
+ function bar();
}
interface b {
- function foo();
+ function foo();
}
abstract class c {
- function bar() { }
+ function bar() { }
}
class x extends c implements a, b {
- function foo() { }
+ function foo() { }
}
trait T1 {
- static function foo() {
- var_dump(__METHOD__);
- }
+ static function foo() {
+ var_dump(__METHOD__);
+ }
}
trait T2 {
- use T1;
- static function bar() {
- var_dump(__METHOD__);
- }
+ use T1;
+ static function bar() {
+ var_dump(__METHOD__);
+ }
}
class Y {
- use T2;
+ use T2;
}
class Z {
@@ -50,9 +50,9 @@ function get_anon() {
}
if (!isset($rt)) {
- eval("class Foo {}");
+ eval("class Foo {}");
- class Bar extends Foo {}
+ class Bar extends Foo {}
- eval("function f3() {} ");
+ eval("function f3() {} ");
}
diff --git a/ext/opcache/tests/preload_009.phpt b/ext/opcache/tests/preload_009.phpt
index f3a28675e3..9422295814 100644
--- a/ext/opcache/tests/preload_009.phpt
+++ b/ext/opcache/tests/preload_009.phpt
@@ -16,6 +16,6 @@ var_dump(trait_exists('T'));
var_dump(class_exists('Foo'));
?>
--EXPECTF--
-Warning: Use of undefined constant UNDEF - assumed 'UNDEF' (this will throw an Error in a future version of PHP) in Unknown on line 0
-bool(true)
-bool(true)
+Fatal error: Undefined constant 'UNDEF' in Unknown on line 0
+
+Fatal error: Failed to resolve initializers of class Foo during preloading in Unknown on line 0
diff --git a/ext/opcache/tests/preload_011.phpt b/ext/opcache/tests/preload_011.phpt
index 59be0493b4..9beab03082 100644
--- a/ext/opcache/tests/preload_011.phpt
+++ b/ext/opcache/tests/preload_011.phpt
@@ -23,11 +23,9 @@ $f = new F;
$g = new G;
?>
-===DONE===
--EXPECTF--
Warning: Can't preload unlinked class H: Unknown type dependencies in %s on line %d
Warning: Can't preload unlinked class B: Unknown type dependencies in %s on line %d
Warning: Can't preload unlinked class A: Unknown type dependencies in %s on line %d
-===DONE===
diff --git a/ext/opcache/tests/preload_012.phpt b/ext/opcache/tests/preload_012.phpt
index bd3fd81bbd..7c5ad9aa1a 100644
--- a/ext/opcache/tests/preload_012.phpt
+++ b/ext/opcache/tests/preload_012.phpt
@@ -11,7 +11,5 @@ require_once('skipif.inc');
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
?>
--FILE--
-===DONE===
--EXPECTF--
Warning: Can't preload class Test with unresolved initializer for constant C in %s on line %d
-===DONE===
diff --git a/ext/opcache/tests/preload_bug78014.inc b/ext/opcache/tests/preload_bug78014.inc
index 84cc1d90c8..9c469a72b6 100644
--- a/ext/opcache/tests/preload_bug78014.inc
+++ b/ext/opcache/tests/preload_bug78014.inc
@@ -1,2 +1,2 @@
-<?php
+<?php
opcache_compile_file(__DIR__ . "/bug78014.inc");
diff --git a/ext/opcache/tests/preload_bug78175_2.inc b/ext/opcache/tests/preload_bug78175_2.inc
index a960e1b08c..cc99105457 100644
--- a/ext/opcache/tests/preload_bug78175_2.inc
+++ b/ext/opcache/tests/preload_bug78175_2.inc
@@ -1,18 +1,18 @@
<?php
class Loader {
- static private $loader;
+ static private $loader;
- static function getLoader() {
- if (null !== self::$loader) {
- return self::$loader;
- }
- return self::$loader = new Loader();
- }
+ static function getLoader() {
+ if (null !== self::$loader) {
+ return self::$loader;
+ }
+ return self::$loader = new Loader();
+ }
- static function getCounter() {
- static $counter = 0;
- return $counter++;
- }
+ static function getCounter() {
+ static $counter = 0;
+ return $counter++;
+ }
}
class ExtLoader extends Loader {
diff --git a/ext/opcache/tests/preload_bug78376.inc b/ext/opcache/tests/preload_bug78376.inc
index c482e0a821..87145ba3c5 100644
--- a/ext/opcache/tests/preload_bug78376.inc
+++ b/ext/opcache/tests/preload_bug78376.inc
@@ -1,6 +1,6 @@
<?php
const CNST = 'aaaa';
class A {
- public static $a = CNST;
+ public static $a = CNST;
}
$a = \A::$a;
diff --git a/ext/opcache/tests/preload_bug78937.inc b/ext/opcache/tests/preload_bug78937.inc
index 7da2dc3227..49acbb1a66 100644
--- a/ext/opcache/tests/preload_bug78937.inc
+++ b/ext/opcache/tests/preload_bug78937.inc
@@ -3,6 +3,6 @@ function foo() {
return new class extends Bar {};
}
function bar() {
- class Foo extends Bar {
- }
+ class Foo extends Bar {
+ }
}
diff --git a/ext/opcache/tests/preload_globals.inc b/ext/opcache/tests/preload_globals.inc
index 213dc60fab..7ae442dc03 100644
--- a/ext/opcache/tests/preload_globals.inc
+++ b/ext/opcache/tests/preload_globals.inc
@@ -1,5 +1,5 @@
<?php
function get_x() {
- return $GLOBALS["x"];
+ return $GLOBALS["x"];
}
diff --git a/ext/opcache/tests/preload_loadable_classes_2.phpt b/ext/opcache/tests/preload_loadable_classes_2.phpt
index d561837bd0..c1f873ec47 100644
--- a/ext/opcache/tests/preload_loadable_classes_2.phpt
+++ b/ext/opcache/tests/preload_loadable_classes_2.phpt
@@ -13,8 +13,6 @@ if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows
--FILE--
Unreachable
--EXPECTF--
-Warning: Use of undefined constant UNDEF - assumed 'UNDEF' (this will throw an Error in a future version of PHP) in Unknown on line 0
-
-Fatal error: Class 'Foo' not found in Unknown on line 0
+Fatal error: Undefined constant 'UNDEF' in Unknown on line 0
Fatal error: Failed to resolve initializers of class Test during preloading in Unknown on line 0
diff --git a/ext/opcache/tests/revalidate_path_01.phpt b/ext/opcache/tests/revalidate_path_01.phpt
index d982613103..317e872a4c 100644
--- a/ext/opcache/tests/revalidate_path_01.phpt
+++ b/ext/opcache/tests/revalidate_path_01.phpt
@@ -6,7 +6,6 @@ opcache.enable_cli=1
opcache.revalidate_path=1
--SKIPIF--
<?php require_once('skipif.inc'); ?>
-<?php if (php_sapi_name() != "cli") die("skip CLI only"); ?>
--CONFLICTS--
server
--FILE--
@@ -24,17 +23,17 @@ $main = "$dir/main.php";
@file_put_contents($file1, "TEST 1\n");
@file_put_contents($file2, "TEST 2\n");
while (filemtime($file1) != filemtime($file2)) {
- touch($file1);
- touch($file2);
+ touch($file1);
+ touch($file2);
}
if (substr(PHP_OS, 0, 3) == 'WIN') {
- @rmdir($link);
- $ln = str_replace('/', '\\', $link);
- $d1 = realpath($dir1);
- `mklink /j $ln $d1`;
+ @rmdir($link);
+ $ln = str_replace('/', '\\', $link);
+ $d1 = realpath($dir1);
+ `mklink /j $ln $d1`;
} else {
- @unlink($link);
- @symlink($dir1, $link);
+ @unlink($link);
+ @symlink($dir1, $link);
}
include "php_cli_server.inc";
@@ -43,13 +42,13 @@ php_cli_server_start('-d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.rev
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php');
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php');
if (substr(PHP_OS, 0, 3) == 'WIN') {
- @rmdir($link);
- $ln = str_replace('/', '\\', $link);
- $d2 = realpath($dir2);
- `mklink /j $ln $d2`;
+ @rmdir($link);
+ $ln = str_replace('/', '\\', $link);
+ $d2 = realpath($dir2);
+ `mklink /j $ln $d2`;
} else {
- @unlink($link);
- @symlink($dir2, $link);
+ @unlink($link);
+ @symlink($dir2, $link);
}
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php');
echo file_get_contents('http://' . PHP_CLI_SERVER_ADDRESS . '/main.php');
diff --git a/ext/opcache/tests/ssa_bug_001.phpt b/ext/opcache/tests/ssa_bug_001.phpt
index 62613e6eee..06be60892c 100644
--- a/ext/opcache/tests/ssa_bug_001.phpt
+++ b/ext/opcache/tests/ssa_bug_001.phpt
@@ -1,5 +1,5 @@
--TEST--
-SSA constrution for CFG with unreachable basic blocks
+SSA construction for CFG with unreachable basic blocks
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
diff --git a/ext/opcache/tests/ssa_bug_007.phpt b/ext/opcache/tests/ssa_bug_007.phpt
index e5237687b2..344a05665d 100644
--- a/ext/opcache/tests/ssa_bug_007.phpt
+++ b/ext/opcache/tests/ssa_bug_007.phpt
@@ -5,18 +5,18 @@ Incorrect CFG/SSA construction for SWITCH with few identical successors
--FILE--
<?php
function render($properties) {
- foreach ($properties as $key => $value) {
- switch ($key) {
- case 'Trapped':
- if ($value == null) {
- $docInfo->$key = 1;
- }
- case 'CreationDate':
- case 'ModDate':
- $docInfo->$key = 2;
- break;
- }
- }
+ foreach ($properties as $key => $value) {
+ switch ($key) {
+ case 'Trapped':
+ if ($value == null) {
+ $docInfo->$key = 1;
+ }
+ case 'CreationDate':
+ case 'ModDate':
+ $docInfo->$key = 2;
+ break;
+ }
+ }
}
?>
OK
diff --git a/ext/opcache/tests/ssa_bug_011.phpt b/ext/opcache/tests/ssa_bug_011.phpt
index c25e9c46ab..253bdc78d5 100644
--- a/ext/opcache/tests/ssa_bug_011.phpt
+++ b/ext/opcache/tests/ssa_bug_011.phpt
@@ -5,11 +5,11 @@ Wrong assertion
--FILE--
<?php
function foo($transitions) {
- foreach ($transitions as $transition) {
- if (isEmpty()) {
- continue;
- }
- }
+ foreach ($transitions as $transition) {
+ if (isEmpty()) {
+ continue;
+ }
+ }
}
?>
OK
diff --git a/ext/opcache/tests/wrong_inlining_002.phpt b/ext/opcache/tests/wrong_inlining_002.phpt
index 4e71a96d10..9aaa60c534 100644
--- a/ext/opcache/tests/wrong_inlining_002.phpt
+++ b/ext/opcache/tests/wrong_inlining_002.phpt
@@ -20,10 +20,7 @@ class Foo {
Foo::test();
?>
--EXPECTF--
-Deprecated: Non-static method Foo::test() should not be called statically in %swrong_inlining_002.php on line 11
-
-Fatal error: Uncaught Error: Using $this when not in object context in %swrong_inlining_002.php:7
+Fatal error: Uncaught Error: Non-static method Foo::test() cannot be called statically in %s:%d
Stack trace:
-#0 %swrong_inlining_002.php(11): Foo::test()
-#1 {main}
- thrown in %swrong_inlining_002.php on line 7
+#0 {main}
+ thrown in %s on line %d
diff --git a/ext/opcache/tests/wrong_inlining_003.phpt b/ext/opcache/tests/wrong_inlining_003.phpt
index a7e4a11b76..c83a4efc36 100644
--- a/ext/opcache/tests/wrong_inlining_003.phpt
+++ b/ext/opcache/tests/wrong_inlining_003.phpt
@@ -19,5 +19,5 @@ function test() {
test();
?>
--EXPECTF--
-Notice: Undefined variable: undef in %swrong_inlining_003.php on line 7
+Warning: Undefined variable: undef in %s on line %d
int(42)
diff --git a/ext/opcache/tests/wrong_inlining_004.phpt b/ext/opcache/tests/wrong_inlining_004.phpt
index 8ecb87cd4f..26f8f4b2bf 100644
--- a/ext/opcache/tests/wrong_inlining_004.phpt
+++ b/ext/opcache/tests/wrong_inlining_004.phpt
@@ -1,5 +1,5 @@
--TEST--
-Inlining throgh call_user_func()
+Inlining through call_user_func()
--INI--
opcache.enable=1
opcache.enable_cli=1
diff --git a/ext/opcache/zend_accelerator_debug.c b/ext/opcache/zend_accelerator_debug.c
index 991f2329da..f91c269975 100644
--- a/ext/opcache/zend_accelerator_debug.c
+++ b/ext/opcache/zend_accelerator_debug.c
@@ -47,7 +47,7 @@ void zend_accel_error(int type, const char *format, ...)
fLog = stderr;
} else {
- fLog = fopen(ZCG(accel_directives).error_log, "a+");
+ fLog = fopen(ZCG(accel_directives).error_log, "a");
if (!fLog) {
fLog = stderr;
}
diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c
index 7d04e49f32..c3bb66bdb1 100644
--- a/ext/opcache/zend_accelerator_module.c
+++ b/ext/opcache/zend_accelerator_module.c
@@ -31,6 +31,11 @@
#include "zend_virtual_cwd.h"
#include "ext/standard/info.h"
#include "ext/standard/php_filestat.h"
+#include "opcache_arginfo.h"
+
+#if HAVE_JIT
+#include "jit/zend_jit.h"
+#endif
#define STRING_NOT_NULL(s) (NULL == (s)?"":s)
#define MIN_ACCEL_FILES 200
@@ -41,26 +46,6 @@ static zif_handler orig_file_exists = NULL;
static zif_handler orig_is_file = NULL;
static zif_handler orig_is_readable = NULL;
-ZEND_BEGIN_ARG_INFO(arginfo_opcache_none, 0)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_get_status, 0, 0, 0)
- ZEND_ARG_INFO(0, fetch_scripts)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_compile_file, 0, 0, 1)
- ZEND_ARG_INFO(0, file)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_invalidate, 0, 0, 1)
- ZEND_ARG_INFO(0, script)
- ZEND_ARG_INFO(0, force)
-ZEND_END_ARG_INFO()
-
-ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_is_script_cached, 0, 0, 1)
- ZEND_ARG_INFO(0, script)
-ZEND_END_ARG_INFO()
-
/* User functions */
static ZEND_FUNCTION(opcache_reset);
static ZEND_FUNCTION(opcache_invalidate);
@@ -73,12 +58,12 @@ static ZEND_FUNCTION(opcache_get_configuration);
static const zend_function_entry accel_functions[] = {
/* User functions */
- ZEND_FE(opcache_reset, arginfo_opcache_none)
+ ZEND_FE(opcache_reset, arginfo_opcache_reset)
ZEND_FE(opcache_invalidate, arginfo_opcache_invalidate)
ZEND_FE(opcache_compile_file, arginfo_opcache_compile_file)
ZEND_FE(opcache_is_script_cached, arginfo_opcache_is_script_cached)
/* Private functions */
- ZEND_FE(opcache_get_configuration, arginfo_opcache_none)
+ ZEND_FE(opcache_get_configuration, arginfo_opcache_get_configuration)
ZEND_FE(opcache_get_status, arginfo_opcache_get_status)
ZEND_FE_END
};
@@ -327,6 +312,12 @@ ZEND_INI_BEGIN()
#if ZEND_WIN32
STD_PHP_INI_ENTRY("opcache.cache_id" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.cache_id, zend_accel_globals, accel_globals)
#endif
+#ifdef HAVE_JIT
+ STD_PHP_INI_ENTRY("opcache.jit" , ZEND_JIT_DEFAULT, PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.jit_buffer_size" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit_buffer_size, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.jit_debug" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit_debug, zend_accel_globals, accel_globals)
+ STD_PHP_INI_ENTRY("opcache.jit_bisect_limit" , "0" , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.jit_bisect_limit, zend_accel_globals, accel_globals)
+#endif
ZEND_INI_END()
static int filename_is_in_cache(zend_string *filename)
@@ -457,6 +448,15 @@ void zend_accel_info(ZEND_MODULE_INFO_FUNC_ARGS)
} else {
php_info_print_table_row(2, "File Cache", "Disabled");
}
+#if HAVE_JIT
+ if (ZCG(jit_enabled)) {
+ php_info_print_table_row(2, "JIT", "Enabled");
+ } else {
+ php_info_print_table_row(2, "JIT", "Disabled");
+ }
+#else
+ php_info_print_table_row(2, "JIT", "Not Available");
+#endif
if (file_cache_only) {
if (!accel_startup_ok || zps_api_failure_reason) {
php_info_print_table_row(2, "Startup Failed", zps_api_failure_reason);
@@ -585,7 +585,7 @@ static ZEND_FUNCTION(opcache_get_status)
zend_bool fetch_scripts = 1;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &fetch_scripts) == FAILURE) {
- return;
+ RETURN_THROWS();
}
if (!validate_api_restriction()) {
@@ -699,6 +699,9 @@ static ZEND_FUNCTION(opcache_get_status)
add_assoc_zval(return_value, "scripts", &scripts);
}
}
+#if HAVE_JIT
+ zend_jit_status(return_value);
+#endif
}
static int add_blacklist_path(zend_blacklist_entry *p, zval *return_value)
@@ -714,7 +717,7 @@ static ZEND_FUNCTION(opcache_get_configuration)
zval directives, version, blacklist;
if (zend_parse_parameters_none() == FAILURE) {
- RETURN_FALSE;
+ RETURN_THROWS();
}
if (!validate_api_restriction()) {
@@ -780,6 +783,12 @@ static ZEND_FUNCTION(opcache_get_configuration)
#if ZEND_WIN32
add_assoc_string(&directives, "opcache.cache_id", STRING_NOT_NULL(ZCG(accel_directives).cache_id));
#endif
+#ifdef HAVE_JIT
+ add_assoc_long(&directives, "opcache.jit", ZCG(accel_directives).jit);
+ add_assoc_long(&directives, "opcache.jit_buffer_size", ZCG(accel_directives).jit_buffer_size);
+ add_assoc_long(&directives, "opcache.jit_debug", ZCG(accel_directives).jit_debug);
+ add_assoc_long(&directives, "opcache.jit_bisect_limit", ZCG(accel_directives).jit_bisect_limit);
+#endif
add_assoc_zval(return_value, "directives", &directives);
@@ -800,7 +809,7 @@ static ZEND_FUNCTION(opcache_get_configuration)
static ZEND_FUNCTION(opcache_reset)
{
if (zend_parse_parameters_none() == FAILURE) {
- RETURN_FALSE;
+ RETURN_THROWS();
}
if (!validate_api_restriction()) {
@@ -831,7 +840,7 @@ static ZEND_FUNCTION(opcache_invalidate)
zend_bool force = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &script_name, &script_name_len, &force) == FAILURE) {
- return;
+ RETURN_THROWS();
}
if (!validate_api_restriction()) {
@@ -855,7 +864,7 @@ static ZEND_FUNCTION(opcache_compile_file)
uint32_t orig_compiler_options;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &script_name, &script_name_len) == FAILURE) {
- return;
+ RETURN_THROWS();
}
if (!accel_startup_ok) {
@@ -910,7 +919,7 @@ static ZEND_FUNCTION(opcache_is_script_cached)
}
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &script_name) == FAILURE) {
- return;
+ RETURN_THROWS();
}
RETURN_BOOL(filename_is_in_cache(script_name));
diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c
index 53efa865c7..131fc8495b 100644
--- a/ext/opcache/zend_accelerator_util_funcs.c
+++ b/ext/opcache/zend_accelerator_util_funcs.c
@@ -233,11 +233,28 @@ static void zend_hash_clone_prop_info(HashTable *ht)
prop_info->ce = ARENA_REALLOC(prop_info->ce);
}
- if (ZEND_TYPE_IS_CE(prop_info->type)) {
+ if (ZEND_TYPE_HAS_LIST(prop_info->type)) {
+ zend_type_list *list = ZEND_TYPE_LIST(prop_info->type);
+ if (IN_ARENA(list)) {
+ list = ARENA_REALLOC(list);
+ ZEND_TYPE_SET_PTR(prop_info->type, list);
+
+ zend_type *list_type;
+ ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(prop_info->type), list_type) {
+ if (ZEND_TYPE_HAS_CE(*list_type)) {
+ zend_class_entry *ce = ZEND_TYPE_CE(*list_type);
+ if (IN_ARENA(ce)) {
+ ce = ARENA_REALLOC(ce);
+ ZEND_TYPE_SET_PTR(*list_type, ce);
+ }
+ }
+ } ZEND_TYPE_LIST_FOREACH_END();
+ }
+ } else if (ZEND_TYPE_HAS_CE(prop_info->type)) {
zend_class_entry *ce = ZEND_TYPE_CE(prop_info->type);
if (IN_ARENA(ce)) {
ce = ARENA_REALLOC(ce);
- prop_info->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop_info->type));
+ ZEND_TYPE_SET_PTR(prop_info->type, ce);
}
}
}
diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c
index 18c69288b3..eb74187e5d 100644
--- a/ext/opcache/zend_file_cache.c
+++ b/ext/opcache/zend_file_cache.c
@@ -371,26 +371,27 @@ static void zend_file_cache_serialize_zval(zval *zv,
}
}
-/* Adjust serialized pointer to conform to zend_type assumptions:
- * Pointer must have low two bits unset and be larger than 0x400. */
-#define ZEND_TYPE_PTR_ENCODE(ptr) \
- (void*)(((uintptr_t)ptr << 2) + 0x400)
-#define ZEND_TYPE_PTR_DECODE(ptr) \
- (void*)(((uintptr_t)ptr - 0x400) >> 2)
-
static void zend_file_cache_serialize_type(
zend_type *type, zend_persistent_script *script, zend_file_cache_metainfo *info, void *buf)
{
- if (ZEND_TYPE_IS_NAME(*type)) {
- zend_string *name = ZEND_TYPE_NAME(*type);
- SERIALIZE_STR(name);
- name = ZEND_TYPE_PTR_ENCODE(name);
- *type = ZEND_TYPE_ENCODE_CLASS(name, ZEND_TYPE_ALLOW_NULL(*type));
- } else if (ZEND_TYPE_IS_CE(*type)) {
+ if (ZEND_TYPE_HAS_LIST(*type)) {
+ zend_type_list *list = ZEND_TYPE_LIST(*type);
+ SERIALIZE_PTR(list);
+ ZEND_TYPE_SET_PTR(*type, list);
+ UNSERIALIZE_PTR(list);
+
+ zend_type *list_type;
+ ZEND_TYPE_LIST_FOREACH(list, list_type) {
+ zend_file_cache_serialize_type(list_type, script, info, buf);
+ } ZEND_TYPE_LIST_FOREACH_END();
+ } else if (ZEND_TYPE_HAS_NAME(*type)) {
+ zend_string *type_name = ZEND_TYPE_NAME(*type);
+ SERIALIZE_STR(type_name);
+ ZEND_TYPE_SET_PTR(*type, type_name);
+ } else if (ZEND_TYPE_HAS_CE(*type)) {
zend_class_entry *ce = ZEND_TYPE_CE(*type);
SERIALIZE_PTR(ce);
- ce = ZEND_TYPE_PTR_ENCODE(ce);
- *type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(*type));
+ ZEND_TYPE_SET_PTR(*type, ce);
}
}
@@ -590,8 +591,8 @@ static void zend_file_cache_serialize_prop_info(zval *zv,
if (prop->doc_comment) {
SERIALIZE_STR(prop->doc_comment);
}
+ zend_file_cache_serialize_type(&prop->type, script, info, buf);
}
- zend_file_cache_serialize_type(&prop->type, script, info, buf);
}
}
@@ -889,6 +890,13 @@ int zend_file_cache_script_store(zend_persistent_script *script, int in_shm)
#endif
void *mem, *buf;
+#ifdef HAVE_JIT
+ /* FIXME: dump jited codes out to file cache? */
+ if (ZCG(jit_enabled)) {
+ return FAILURE;
+ }
+#endif
+
filename = zend_file_cache_get_bin_file_path(script->script.filename);
if (zend_file_cache_mkdir(filename, strlen(ZCG(accel_directives).file_cache)) != SUCCESS) {
@@ -1087,16 +1095,23 @@ static void zend_file_cache_unserialize_zval(zval *zv,
static void zend_file_cache_unserialize_type(
zend_type *type, zend_persistent_script *script, void *buf)
{
- if (ZEND_TYPE_IS_NAME(*type)) {
- zend_string *name = ZEND_TYPE_NAME(*type);
- name = ZEND_TYPE_PTR_DECODE(name);
- UNSERIALIZE_STR(name);
- *type = ZEND_TYPE_ENCODE_CLASS(name, ZEND_TYPE_ALLOW_NULL(*type));
- } else if (ZEND_TYPE_IS_CE(*type)) {
+ if (ZEND_TYPE_HAS_LIST(*type)) {
+ zend_type_list *list = ZEND_TYPE_LIST(*type);
+ UNSERIALIZE_PTR(list);
+ ZEND_TYPE_SET_PTR(*type, list);
+
+ zend_type *list_type;
+ ZEND_TYPE_LIST_FOREACH(list, list_type) {
+ zend_file_cache_unserialize_type(list_type, script, buf);
+ } ZEND_TYPE_LIST_FOREACH_END();
+ } else if (ZEND_TYPE_HAS_NAME(*type)) {
+ zend_string *type_name = ZEND_TYPE_NAME(*type);
+ UNSERIALIZE_STR(type_name);
+ ZEND_TYPE_SET_PTR(*type, type_name);
+ } else if (ZEND_TYPE_HAS_CE(*type)) {
zend_class_entry *ce = ZEND_TYPE_CE(*type);
- ce = ZEND_TYPE_PTR_DECODE(ce);
UNSERIALIZE_PTR(ce);
- *type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(*type));
+ ZEND_TYPE_SET_PTR(*type, ce);
}
}
@@ -1292,8 +1307,8 @@ static void zend_file_cache_unserialize_prop_info(zval *zv,
if (prop->doc_comment) {
UNSERIALIZE_STR(prop->doc_comment);
}
+ zend_file_cache_unserialize_type(&prop->type, script, buf);
}
- zend_file_cache_unserialize_type(&prop->type, script, buf);
}
}
diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c
index dd4c199ef7..1bcec7caf0 100644
--- a/ext/opcache/zend_persist.c
+++ b/ext/opcache/zend_persist.c
@@ -29,6 +29,10 @@
#include "zend_operators.h"
#include "zend_interfaces.h"
+#ifdef HAVE_JIT
+# include "jit/zend_jit.h"
+#endif
+
#define zend_set_str_gc_flags(str) do { \
if (file_cache_only) { \
GC_TYPE_INFO(str) = IS_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT); \
@@ -254,6 +258,35 @@ static void zend_persist_zval(zval *z)
}
}
+static void zend_persist_type(zend_type *type) {
+ if (ZEND_TYPE_HAS_LIST(*type)) {
+ zend_type *list_type;
+ zend_type_list *list = ZEND_TYPE_LIST(*type);
+ if (ZEND_TYPE_USES_ARENA(*type)) {
+ if (!ZCG(is_immutable_class)) {
+ list = zend_shared_memdup_arena_put(list, ZEND_TYPE_LIST_SIZE(list->num_types));
+ } else {
+ /* Moved from arena to SHM because type list was fully resolved. */
+ list = zend_shared_memdup_put(list, ZEND_TYPE_LIST_SIZE(list->num_types));
+ ZEND_TYPE_FULL_MASK(*type) &= ~_ZEND_TYPE_ARENA_BIT;
+ }
+ } else {
+ list = zend_shared_memdup_put_free(list, ZEND_TYPE_LIST_SIZE(list->num_types));
+ }
+ ZEND_TYPE_SET_PTR(*type, list);
+
+ ZEND_TYPE_LIST_FOREACH(list, list_type) {
+ zend_string *type_name = ZEND_TYPE_NAME(*list_type);
+ zend_accel_store_interned_string(type_name);
+ ZEND_TYPE_SET_PTR(*list_type, type_name);
+ } ZEND_TYPE_LIST_FOREACH_END();
+ } else if (ZEND_TYPE_HAS_NAME(*type)) {
+ zend_string *type_name = ZEND_TYPE_NAME(*type);
+ zend_accel_store_interned_string(type_name);
+ ZEND_TYPE_SET_PTR(*type, type_name);
+ }
+}
+
static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script)
{
zend_op *persist_ptr;
@@ -495,13 +528,7 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
if (arg_info[i].name) {
zend_accel_store_interned_string(arg_info[i].name);
}
- if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) {
- zend_string *type_name = ZEND_TYPE_NAME(arg_info[i].type);
- zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type);
-
- zend_accel_store_interned_string(type_name);
- arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(type_name, allow_null);
- }
+ zend_persist_type(&arg_info[i].type);
}
if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
arg_info++;
@@ -535,6 +562,14 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc
}
ZCG(mem) = (void*)((char*)ZCG(mem) + ZEND_ALIGNED_SIZE(zend_extensions_op_array_persist(op_array, ZCG(mem))));
+
+#ifdef HAVE_JIT
+ if (ZCG(jit_enabled) &&
+ ZEND_JIT_LEVEL(ZCG(accel_directives).jit) <= ZEND_JIT_LEVEL_OPT_FUNCS &&
+ !ZCG(current_persistent_script)->corrupted) {
+ zend_jit_op_array(op_array, ZCG(current_persistent_script) ? &ZCG(current_persistent_script)->script : NULL);
+ }
+#endif
}
static void zend_persist_op_array(zval *zv)
@@ -648,12 +683,7 @@ static void zend_persist_property_info(zval *zv)
prop->doc_comment = NULL;
}
}
-
- if (ZEND_TYPE_IS_NAME(prop->type)) {
- zend_string *class_name = ZEND_TYPE_NAME(prop->type);
- zend_accel_store_interned_string(class_name);
- prop->type = ZEND_TYPE_ENCODE_CLASS(class_name, ZEND_TYPE_ALLOW_NULL(prop->type));
- }
+ zend_persist_type(&prop->type);
}
static void zend_persist_class_constant(zval *zv)
@@ -917,10 +947,10 @@ static void zend_update_parent_ce(zend_class_entry *ce)
if (ce->iterator_funcs_ptr) {
memset(ce->iterator_funcs_ptr, 0, sizeof(zend_class_iterator_funcs));
- if (instanceof_function_ex(ce, zend_ce_aggregate, 1)) {
+ if (zend_class_implements_interface(ce, zend_ce_aggregate)) {
ce->iterator_funcs_ptr->zf_new_iterator = zend_hash_str_find_ptr(&ce->function_table, "getiterator", sizeof("getiterator") - 1);
}
- if (instanceof_function_ex(ce, zend_ce_iterator, 1)) {
+ if (zend_class_implements_interface(ce, zend_ce_iterator)) {
ce->iterator_funcs_ptr->zf_rewind = zend_hash_str_find_ptr(&ce->function_table, "rewind", sizeof("rewind") - 1);
ce->iterator_funcs_ptr->zf_valid = zend_hash_str_find_ptr(&ce->function_table, "valid", sizeof("valid") - 1);
ce->iterator_funcs_ptr->zf_key = zend_hash_str_find_ptr(&ce->function_table, "key", sizeof("key") - 1);
@@ -933,15 +963,18 @@ static void zend_update_parent_ce(zend_class_entry *ce)
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
zend_property_info *prop;
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
- if (ZEND_TYPE_IS_CE(prop->type)) {
- zend_class_entry *ce = ZEND_TYPE_CE(prop->type);
- if (ce->type == ZEND_USER_CLASS) {
- ce = zend_shared_alloc_get_xlat_entry(ce);
- if (ce) {
- prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type));
+ zend_type *single_type;
+ ZEND_TYPE_FOREACH(prop->type, single_type) {
+ if (ZEND_TYPE_HAS_CE(*single_type)) {
+ zend_class_entry *ce = ZEND_TYPE_CE(*single_type);
+ if (ce->type == ZEND_USER_CLASS) {
+ ce = zend_shared_alloc_get_xlat_entry(ce);
+ if (ce) {
+ ZEND_TYPE_SET_PTR(*single_type, ce);
+ }
}
}
- }
+ } ZEND_TYPE_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}
@@ -1078,6 +1111,12 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
script->arena_mem = ZCG(arena_mem) = ZCG(mem);
ZCG(mem) = (void*)((char*)ZCG(mem) + script->arena_size);
+#ifdef HAVE_JIT
+ if (ZCG(jit_enabled) && for_shm) {
+ zend_jit_unprotect();
+ }
+#endif
+
zend_map_ptr_extend(ZCSG(map_ptr_last));
zend_accel_persist_class_table(&script->script.class_table);
@@ -1093,6 +1132,15 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
ZCSG(map_ptr_last) = CG(map_ptr_last);
}
+#ifdef HAVE_JIT
+ if (ZCG(jit_enabled) && for_shm) {
+ if (ZEND_JIT_LEVEL(ZCG(accel_directives).jit) >= ZEND_JIT_LEVEL_OPT_SCRIPT) {
+ zend_jit_script(&script->script);
+ }
+ zend_jit_protect();
+ }
+#endif
+
script->corrupted = 0;
ZCG(current_persistent_script) = NULL;
diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c
index dacc2376e8..293af3b3e6 100644
--- a/ext/opcache/zend_persist_calc.c
+++ b/ext/opcache/zend_persist_calc.c
@@ -148,6 +148,27 @@ static void zend_persist_zval_calc(zval *z)
}
}
+static void zend_persist_type_calc(zend_type *type)
+{
+ if (ZEND_TYPE_HAS_LIST(*type)) {
+ zend_type *list_type;
+ if (ZEND_TYPE_USES_ARENA(*type) && !ZCG(is_immutable_class)) {
+ ADD_ARENA_SIZE(ZEND_TYPE_LIST_SIZE(ZEND_TYPE_LIST(*type)->num_types));
+ } else {
+ ADD_SIZE(ZEND_TYPE_LIST_SIZE(ZEND_TYPE_LIST(*type)->num_types));
+ }
+ ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(*type), list_type) {
+ zend_string *type_name = ZEND_TYPE_NAME(*list_type);
+ ADD_INTERNED_STRING(type_name);
+ ZEND_TYPE_SET_PTR(*list_type, type_name);
+ } ZEND_TYPE_LIST_FOREACH_END();
+ } else if (ZEND_TYPE_HAS_NAME(*type)) {
+ zend_string *type_name = ZEND_TYPE_NAME(*type);
+ ADD_INTERNED_STRING(type_name);
+ ZEND_TYPE_SET_PTR(*type, type_name);
+ }
+}
+
static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
{
if (op_array->scope && zend_shared_alloc_get_xlat_entry(op_array->opcodes)) {
@@ -222,13 +243,7 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array)
if (arg_info[i].name) {
ADD_INTERNED_STRING(arg_info[i].name);
}
- if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) {
- zend_string *type_name = ZEND_TYPE_NAME(arg_info[i].type);
- zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type);
-
- ADD_INTERNED_STRING(type_name);
- arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(type_name, allow_null);
- }
+ zend_persist_type_calc(&arg_info[i].type);
}
}
@@ -304,11 +319,7 @@ static void zend_persist_property_info_calc(zval *zv)
zend_shared_alloc_register_xlat_entry(prop, prop);
ADD_SIZE_EX(sizeof(zend_property_info));
ADD_INTERNED_STRING(prop->name);
- if (ZEND_TYPE_IS_NAME(prop->type)) {
- zend_string *class_name = ZEND_TYPE_NAME(prop->type);
- ADD_INTERNED_STRING(class_name);
- prop->type = ZEND_TYPE_ENCODE_CLASS(class_name, ZEND_TYPE_ALLOW_NULL(prop->type));
- }
+ zend_persist_type_calc(&prop->type);
if (ZCG(accel_directives).save_comments && prop->doc_comment) {
ADD_STRING(prop->doc_comment);
}
@@ -338,9 +349,12 @@ static void check_property_type_resolution(zend_class_entry *ce) {
if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
- if (ZEND_TYPE_IS_NAME(prop->type)) {
- return;
- }
+ zend_type *single_type;
+ ZEND_TYPE_FOREACH(prop->type, single_type) {
+ if (ZEND_TYPE_HAS_NAME(*single_type)) {
+ return;
+ }
+ } ZEND_TYPE_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}
ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c
index 8e75cda333..d32a70b7e8 100644
--- a/ext/opcache/zend_shared_alloc.c
+++ b/ext/opcache/zend_shared_alloc.c
@@ -145,7 +145,7 @@ static int zend_shared_alloc_try(const zend_shared_memory_handler_entry *he, siz
return ALLOC_FAILURE;
}
-int zend_shared_alloc_startup(size_t requested_size)
+int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size)
{
zend_shared_segment **tmp_shared_segments;
size_t shared_segments_array_size;
@@ -153,13 +153,13 @@ int zend_shared_alloc_startup(size_t requested_size)
char *error_in = NULL;
const zend_shared_memory_handler_entry *he;
int res = ALLOC_FAILURE;
-
+ int i;
/* shared_free must be valid before we call zend_shared_alloc()
* - make it temporarily point to a local variable
*/
smm_shared_globals = &tmp_shared_globals;
- ZSMMG(shared_free) = requested_size; /* goes to tmp_shared_globals.shared_free */
+ ZSMMG(shared_free) = requested_size - reserved_size; /* goes to tmp_shared_globals.shared_free */
#ifndef ZEND_WIN32
zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path);
@@ -220,10 +220,15 @@ int zend_shared_alloc_startup(size_t requested_size)
}
#endif
+ for (i = 0; i < ZSMMG(shared_segments_count); i++) {
+ ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size;
+ }
+
shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)();
/* move shared_segments and shared_free to shared memory */
ZCG(locked) = 1; /* no need to perform a real lock at this point */
+
p_tmp_shared_globals = (zend_smm_shared_globals *) zend_shared_alloc(sizeof(zend_smm_shared_globals));
if (!p_tmp_shared_globals) {
zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
@@ -251,6 +256,18 @@ int zend_shared_alloc_startup(size_t requested_size)
return ALLOC_FAILURE;
}
+ if (reserved_size) {
+ i = ZSMMG(shared_segments_count) - 1;
+ if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= reserved_size) {
+ ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size - reserved_size;
+ ZSMMG(reserved) = (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end;
+ ZSMMG(reserved_size) = reserved_size;
+ } else {
+ zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
+ return ALLOC_FAILURE;
+ }
+ }
+
ZCG(locked) = 0;
return res;
@@ -298,7 +315,7 @@ static size_t zend_shared_alloc_get_largest_free_block(void)
size_t largest_block_size = 0;
for (i = 0; i < ZSMMG(shared_segments_count); i++) {
- size_t block_size = ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos;
+ size_t block_size = ZSMMG(shared_segments)[i]->end - ZSMMG(shared_segments)[i]->pos;
if (block_size>largest_block_size) {
largest_block_size = block_size;
@@ -331,7 +348,7 @@ void *zend_shared_alloc(size_t size)
return NULL;
}
for (i = 0; i < ZSMMG(shared_segments_count); i++) {
- if (ZSMMG(shared_segments)[i]->size - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
+ if (ZSMMG(shared_segments)[i]->end - ZSMMG(shared_segments)[i]->pos >= block_size) { /* found a valid block */
void *retval = (void *) (((char *) ZSMMG(shared_segments)[i]->p) + ZSMMG(shared_segments)[i]->pos);
ZSMMG(shared_segments)[i]->pos += block_size;
@@ -596,7 +613,7 @@ void zend_accel_shared_protect(int mode)
}
for (i = 0; i < ZSMMG(shared_segments_count); i++) {
- mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->size, mode);
+ mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode);
}
#elif defined(ZEND_WIN32)
int i;
@@ -613,7 +630,7 @@ void zend_accel_shared_protect(int mode)
for (i = 0; i < ZSMMG(shared_segments_count); i++) {
DWORD oldProtect;
- if (!VirtualProtect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->size, mode, &oldProtect)) {
+ if (!VirtualProtect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, mode, &oldProtect)) {
zend_accel_error(ACCEL_LOG_ERROR, "Failed to protect memory");
}
}
@@ -630,7 +647,7 @@ int zend_accel_in_shm(void *ptr)
for (i = 0; i < ZSMMG(shared_segments_count); i++) {
if ((char*)ptr >= (char*)ZSMMG(shared_segments)[i]->p &&
- (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->size) {
+ (char*)ptr < (char*)ZSMMG(shared_segments)[i]->p + ZSMMG(shared_segments)[i]->end) {
return 1;
}
}
diff --git a/ext/opcache/zend_shared_alloc.h b/ext/opcache/zend_shared_alloc.h
index 2a77dfbef7..1dbc88d42e 100644
--- a/ext/opcache/zend_shared_alloc.h
+++ b/ext/opcache/zend_shared_alloc.h
@@ -75,6 +75,7 @@
typedef struct _zend_shared_segment {
size_t size;
+ size_t end;
size_t pos; /* position for simple stack allocator */
void *p;
} zend_shared_segment;
@@ -113,6 +114,9 @@ typedef struct _zend_smm_shared_globals {
zend_shared_memory_state shared_memory_state;
/* Pointer to the application's shared data structures */
void *app_shared_globals;
+ /* Reserved shared memory */
+ void *reserved;
+ size_t reserved_size;
} zend_smm_shared_globals;
extern zend_smm_shared_globals *smm_shared_globals;
@@ -121,10 +125,11 @@ extern zend_smm_shared_globals *smm_shared_globals;
#define SHARED_ALLOC_REATTACHED (SUCCESS+1)
-int zend_shared_alloc_startup(size_t requested_size);
+int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size);
void zend_shared_alloc_shutdown(void);
/* allocate shared memory block */
+void *zend_shared_alloc_pages(size_t requested_size);
void *zend_shared_alloc(size_t size);
/* copy into shared memory */