php / php-src

The PHP Interpreter
https://www.php.net
Other
37.93k stars 7.72k forks source link

zend_jit_trace_build_tssa: Assertion `&call->func->op_array == op_array' failed #15178

Closed TRowbotham closed 2 weeks ago

TRowbotham commented 1 month ago

Description

While #15101 is now fixed for me, I am now hitting another assertion zend_jit_trace_build_tssa: Assertion `&call->func->op_array == op_array' with the JIT enabled. I was unsuccessful at creating a reduced reproducer for this issue as well, unfortunately.

Relevant changed ini settings: opcache.enable_cli=1 opcache.memory_consumption=256 opcache.max_accelerated_files=20000 opcache.jit=1255 opcache.jit_buffer_size=256M

Backtrace

php: ./jit/zend_jit_trace.c:2399: zend_jit_trace_build_tssa: Assertion `&call->func->op_array == op_array' failed.

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737294966912) at ./nptl/pthread_kill.c:44
44      ./nptl/pthread_kill.c: No such file or directory.
(gdb) bt
#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737294966912) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=140737294966912) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=140737294966912, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007ffff7405476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff73eb7f3 in __GI_abort () at ./stdlib/abort.c:79
#5  0x00007ffff73eb71b in __assert_fail_base (fmt=0x7ffff75a0130 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n",
    assertion=0x7ffff40f58c8 "&call->func->op_array == op_array", file=0x7ffff40f5314 "./jit/zend_jit_trace.c",
    line=2399, function=<optimized out>) at ./assert/assert.c:92
#6  0x00007ffff73fce96 in __GI___assert_fail (assertion=0x7ffff40f58c8 "&call->func->op_array == op_array",
    file=0x7ffff40f5314 "./jit/zend_jit_trace.c", line=2399,
    function=0x7ffff40f7f70 <__PRETTY_FUNCTION__.17> "zend_jit_trace_build_tssa") at ./assert/assert.c:101
#7  0x00007ffff40a0c59 in zend_jit_trace_build_tssa (trace_buffer=0x7fffffff6ea0, parent_trace=33, exit_num=0,
    script=0x0, op_arrays=0x7fffffff17c0, num_op_arrays_ptr=0x7fffffff14e4) at ./jit/zend_jit_trace.c:2399
#8  0x00007ffff40a7c3a in zend_jit_trace (trace_buffer=0x7fffffff6ea0, parent_trace=33, exit_num=0)
    at ./jit/zend_jit_trace.c:4046
#9  0x00007ffff40c9672 in zend_jit_compile_side_trace (trace_buffer=0x7fffffff6ea0, parent_num=33, exit_num=0,
    polymorphism=0) at ./jit/zend_jit_trace.c:8192
#10 0x00007ffff40ca54f in zend_jit_trace_hot_side (execute_data=0x7ffff44177a0, parent_num=33, exit_num=0)
    at ./jit/zend_jit_trace.c:8413
#11 0x00007ffff40cbc47 in zend_jit_trace_exit (exit_num=0, regs=0x7fffffffaff0) at ./jit/zend_jit_trace.c:8682
#12 0x0000555545400620 in ?? ()
#13 0x00007ffff449c900 in ?? ()
#14 0x000055553654c060 in ?? ()
#15 0x00005555364d36d0 in ?? ()
#16 0x00007ffff4555a00 in ?? ()
#17 0x00007fffffffb100 in ?? ()
#18 0x00007fffffffb350 in ?? ()
#19 0x00005555364d36d0 in ?? ()
#20 0x0000555536553920 in ?? ()
--Type <RET> for more, q to quit, c to continue without paging--c
#21 0x0000000000000001 in ?? ()
#22 0x0000000000000000 in ?? ()

Information about the last complied trace using -d opcache.jit_debug=0x1ff000

---- TRACE 50 start (side trace 38/0) Rowbot\DOM\Parser\HTML\TreeBuilder::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/TreeBuilder.php:43
0014 T3 = FETCH_OBJ_R CV1($adjustedCurrentNode) string("namespaceURI") ; op1(object of class Rowbot\DOM\Element\HTML\HTMLDivElement) val(string)
0015 T4 = FETCH_CLASS_CONSTANT string("Rowbot\\DOM\\Namespaces") string("HTML")
0016 T2 = IS_IDENTICAL T3 T4 ; op1(string) op2(string)
0017 ;JMPNZ T2 0069
0069 T3 = FETCH_OBJ_R THIS string("context") ; val(object)
0070 T2 = FETCH_OBJ_R T3 string("insertionMode") ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext) val(object)
0071 INIT_METHOD_CALL 2 T2 string("processToken") ; op1(object of class Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode)
     >init Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::processToken
0072 CHECK_FUNC_ARG 1
0073 V2 = FETCH_OBJ_FUNC_ARG (ref) THIS string("context") ; val(object)
0074 SEND_FUNC_ARG V2 1 ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext)
0075 SEND_VAR_EX CV0($token) 2 ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken)
0076 DO_FCALL
     >enter Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::processToken
0000  CV0($context) = RECV 1
0001  CV1($token) = RECV 2
0002  T3 = INSTANCEOF CV1($token) string("Rowbot\\DOM\\Parser\\Token\\CharacterToken") ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken)
0003  ;JMPZ T3 0033
0004  T4 = FETCH_OBJ_R CV1($token) string("data") ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken) val(string)
0005  T3 = IS_IDENTICAL T4 string("") ; op1(string)
0006  ;JMPZ T3 0008
0008  INIT_METHOD_CALL 1 THIS string("reconstructActiveFormattingElements")
      >init Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
0009  SEND_VAR CV0($context) 1 ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext)
0010  DO_FCALL
      >enter Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
0000   CV0($context) = RECV 1
0001   T4 = FETCH_OBJ_R CV0($context) string("activeFormattingElements") ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext) val(object)
0002   INIT_METHOD_CALL 0 T4 string("isEmpty") ; op1(object of class Rowbot\DOM\Parser\Collection\ActiveFormattingElementStack)
       >init Rowbot\DOM\Parser\Collection\ObjectStack::isEmpty
0003   V4 = DO_FCALL
       >enter Rowbot\DOM\Parser\Collection\ObjectStack::isEmpty
0000    T1 = FETCH_OBJ_R THIS string("size") ; val(int)
0001    T0 = IS_IDENTICAL T1 int(0) ; op1(int)
0002    RETURN T0 ; op1(bool)
       <back Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
0004   JMPZ V4 0006 ; op1(bool)
0006   T4 = FETCH_OBJ_R CV0($context) string("activeFormattingElements") ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext) val(object)
0007   INIT_METHOD_CALL 0 T4 string("top") ; op1(object of class Rowbot\DOM\Parser\Collection\ActiveFormattingElementStack)
       >init Rowbot\DOM\Parser\Collection\ObjectStack::top
0008   V4 = DO_FCALL
       >enter Rowbot\DOM\Parser\Collection\ObjectStack::top
0000    T1 = FETCH_OBJ_R THIS string("size") ; val(int)
0001    T0 = IS_IDENTICAL T1 int(0) ; op1(int)
0002    ;JMPZ T0 0006
0006    T0 = FETCH_OBJ_R THIS string("size") ; val(int)
0007    T2 = SUB T0 int(1) ; op1(int)
0008    T1 = FETCH_OBJ_R THIS string("stack") ; val(array)
0009    T0 = FETCH_DIM_R T1 T2 ; op1(packed array) op2(int) val(object)
0010    RETURN T0 ; op1(object of class Rowbot\DOM\Parser\Marker)
       <back Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
0009   CV1($entry) = QM_ASSIGN V4 ; op1(object of class Rowbot\DOM\Parser\Marker)
0010   T4 = INSTANCEOF CV1($entry) string("Rowbot\\DOM\\Parser\\Marker") ; op1(object of class Rowbot\DOM\Parser\Marker)
0011   ;JMPNZ T4 0018
0018   RETURN null
      <back Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::processToken
0011  INIT_METHOD_CALL 2 THIS string("insertCharacter")
      >init Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::insertCharacter
0012  SEND_VAR_EX CV0($context) 1 ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext)
0013  SEND_VAR_EX CV1($token) 2 ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken)
0014  DO_FCALL
      >enter Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::insertCharacter
---- TRACE 50 stop (link to 19)
---- TRACE 50 TSSA start (side trace 38/0) Rowbot\DOM\Parser\HTML\TreeBuilder::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/TreeBuilder.php:43
     ;#0.CV0($token) [rc1, rcn, object]
     ;#1.CV1($adjustedCurrentNode) [rc1, rcn, object]
0014 #5.T3 [!rc1, rcn, string] = FETCH_OBJ_R #1.CV1($adjustedCurrentNode) [rc1, rcn, object] string("namespaceURI") ; op1(object of class Rowbot\DOM\Element\HTML\HTMLDivElement) val(string)
0015 #6.T4 [!rc1, rcn, string] = FETCH_CLASS_CONSTANT string("Rowbot\\DOM\\Namespaces") string("HTML")
0016 #7.T2 [bool] = IS_IDENTICAL #5.T3 [!rc1, rcn, string] #6.T4 [!rc1, rcn, string] ; op1(string) op2(string)
0017 ;JMPNZ #7.T2 [bool] 0069
0069 #8.T3 [rcn, object] = FETCH_OBJ_R THIS string("context") ; val(object)
0070 #9.T2 [!rc1, rcn, object] = FETCH_OBJ_R #8.T3 [rcn, object] string("insertionMode") ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext) val(object)
0071 INIT_METHOD_CALL 2 #9.T2 [!rc1, rcn, object] string("processToken") ; op1(object of class Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode)
     >init Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::processToken
0072 CHECK_FUNC_ARG 1
0073 #10.V2 [!rc1, rcn, object] = FETCH_OBJ_FUNC_ARG (ref) THIS string("context") ; val(object)
0074 SEND_FUNC_ARG #10.V2 [!rc1, rcn, object] 1 ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext)
0075 SEND_VAR_EX #0.CV0($token) [rc1, rcn, object] -> #11.CV0($token) NOVAL [rc1, rcn, object] 2 ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken)
0076 DO_FCALL
     >enter Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::processToken
0000  #15.CV0($context) [rc1, rcn, object] = RECV 1
0001  #16.CV1($token) [rc1, rcn, object] = RECV 2
0002  #17.T3 [bool] = INSTANCEOF #16.CV1($token) [rc1, rcn, object] string("Rowbot\\DOM\\Parser\\Token\\CharacterToken") ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken)
0003  ;JMPZ #17.T3 [bool] 0033
0004  #18.T4 [!rc1, rcn, string] = FETCH_OBJ_R #16.CV1($token) [rc1, rcn, object] string("data") ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken) val(string)
0005  #19.T3 [bool] = IS_IDENTICAL #18.T4 [!rc1, rcn, string] string("") ; op1(string)
0006  ;JMPZ #19.T3 [bool] 0008
0008  INIT_METHOD_CALL 1 THIS string("reconstructActiveFormattingElements")
      >init Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
0009  SEND_VAR #15.CV0($context) [rc1, rcn, object] -> #20.CV0($context) [rc1, rcn, object] 1 ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext)
0010  DO_FCALL
      >enter Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
       ;#22.CV1($entry) NOVAL [undef]
0000   #25.CV0($context) [rc1, rcn, object] = RECV 1
0001   #26.T4 [!rc1, rcn, object] = FETCH_OBJ_R #25.CV0($context) [rc1, rcn, object] string("activeFormattingElements") ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext) val(object)
0002   INIT_METHOD_CALL 0 #26.T4 [!rc1, rcn, object] string("isEmpty") ; op1(object of class Rowbot\DOM\Parser\Collection\ActiveFormattingElementStack)
       >init Rowbot\DOM\Parser\Collection\ObjectStack::isEmpty
0003   #27.V4 [false] = DO_FCALL
       >enter Rowbot\DOM\Parser\Collection\ObjectStack::isEmpty
0000    #28.T1 [long] = FETCH_OBJ_R THIS string("size") ; val(int)
0001    #29.T0 [!false] = IS_IDENTICAL #28.T1 [long] int(0) ; op1(int)
0002    RETURN #29.T0 [!false] ; op1(bool)
       <back Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
0004   JMPZ #27.V4 [false] 0006 ; op1(bool)
0006   #30.T4 [!rc1, rcn, object] = FETCH_OBJ_R #25.CV0($context) [rc1, rcn, object] string("activeFormattingElements") ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext) val(object)
0007   INIT_METHOD_CALL 0 #30.T4 [!rc1, rcn, object] string("top") ; op1(object of class Rowbot\DOM\Parser\Collection\ActiveFormattingElementStack)
       >init Rowbot\DOM\Parser\Collection\ObjectStack::top
0008   #31.V4 [rc1, rcn, object] = DO_FCALL
       >enter Rowbot\DOM\Parser\Collection\ObjectStack::top
0000    #32.T1 [long] = FETCH_OBJ_R THIS string("size") ; val(int)
0001    #33.T0 [bool] = IS_IDENTICAL #32.T1 [long] int(0) ; op1(int)
0002    ;JMPZ #33.T0 [bool] 0006
0006    #34.T0 [long] = FETCH_OBJ_R THIS string("size") ; val(int)
0007    #35.T2 [!long] = SUB #34.T0 [long] int(1) ; op1(int)
0008    #36.T1 [rcn, ![empty, packed] array [long] of [any, ref]] = FETCH_OBJ_R THIS string("stack") ; val(array)
0009    #37.T0 [!rcn, object] = FETCH_DIM_R #36.T1 [rcn, ![empty, packed] array [long] of [any, ref]] #35.T2 [!long] ; op1(packed array) op2(int) val(object)
0010    RETURN #37.T0 [!rcn, object] ; op1(object of class Rowbot\DOM\Parser\Marker)
       <back Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::reconstructActiveFormattingElements
0009   QM_ASSIGN #31.V4 [rc1, rcn, object] #22.CV1($entry) NOVAL [undef] -> #38.CV1($entry) [rc1, rcn, object] ; op1(object of class Rowbot\DOM\Parser\Marker)
0010   #39.T4 [bool] = INSTANCEOF #38.CV1($entry) [rc1, rcn, object] string("Rowbot\\DOM\\Parser\\Marker") ; op1(object of class Rowbot\DOM\Parser\Marker)
0011   ;JMPNZ #39.T4 [bool] 0018
0018   RETURN null
      <back Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::processToken
0011  INIT_METHOD_CALL 2 THIS string("insertCharacter")
      >init Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::insertCharacter
0012  SEND_VAR_EX #20.CV0($context) [rc1, rcn, object] -> #40.CV0($context) [rc1, rcn, object] 1 ; op1(object of class Rowbot\DOM\Parser\HTML\TreeBuilderContext)
0013  SEND_VAR_EX #16.CV1($token) [rc1, rcn, object] -> #41.CV1($token) [rc1, rcn, object] 2 ; op1(object of class Rowbot\DOM\Parser\Token\CharacterToken)
0014  DO_FCALL
      >enter Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::insertCharacter
---- TRACE 50 TSSA stop (link to 19)
---- TRACE 50 exit info
     exit_0: 0014/0000/4 CV0($token):object CV1($adjustedCurrentNode):object X3:object
     exit_1: 0015/0004/4 CV0($token):object CV1($adjustedCurrentNode):object X3:unknown(zval_copy(rcx))
     exit_2: 0015/0008/4 CV0($token):object CV1($adjustedCurrentNode):object X3:unknown(zval_copy(rcx))
     exit_3: 0016/0012/4 CV0($token):object CV1($adjustedCurrentNode):object X3:string
     exit_4: 0018/0016/5 CV0($token):object CV1($adjustedCurrentNode):object X3:string X4:string
     exit_5: 0069/0021/5/VM CV0($token):object CV1($adjustedCurrentNode):object X3:string X4:string
     exit_6: 0070/0026/5 CV0($token):object CV1($adjustedCurrentNode):object X3:object X4:string
     exit_7: 0071/0031/5/FREE_OP1 CV0($token):object CV1($adjustedCurrentNode):object X2:unknown(zval_copy(rcx)) X3:object X4:string
     exit_8: 0071/0036/5/FREE_OP1 CV0($token):object CV1($adjustedCurrentNode):object X2:unknown(zval_copy(rcx)) X3:object X4:string
     exit_9: 0071/0041/5/POLY(rax, rdi) CV0($token):object CV1($adjustedCurrentNode):object X2:object X3:object X4:string
     exit_10: 0071/0046/5/VM CV0($token):object CV1($adjustedCurrentNode):object X2:object X3:object X4:string
     exit_11: 0074/0051/5 CV0($token):object CV1($adjustedCurrentNode):object X2:unknown(zval_copy(rcx)) X3:object X4:string
     exit_12: 0074/0056/5 CV0($token):object CV1($adjustedCurrentNode):object X2:unknown(zval_copy(rcx)) X3:object X4:string
     exit_13: 0033/0061/3 CV0($context):object CV1($token):object CV2($el):undef
     exit_14: 0004/0064/3 CV0($context):object CV1($token):object CV2($el):undef
     exit_15: 0005/0067/5 CV0($context):object CV1($token):object CV2($el):undef X4:unknown(zval_copy(rcx))
     exit_16: 0005/0072/5 CV0($context):object CV1($token):object CV2($el):undef X4:unknown(zval_copy(rcx))
     exit_17: 0007/0077/5 CV0($context):object CV1($token):object CV2($el):undef X4:string
     exit_18: 0008/0082/5 CV0($context):object CV1($token):object CV2($el):undef X4:string
     exit_19: 0008/0087/5/VM CV0($context):object CV1($token):object CV2($el):undef X4:string
     exit_20: 0001/0092/4 CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef
     exit_21: 0002/0096/5 CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:unknown(zval_copy(rcx))
     exit_22: 0002/0101/5 CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:unknown(zval_copy(rcx))
     exit_23: 0002/0106/5/POLY(rax, rdi) CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:object
     exit_24: 0002/0111/5/VM CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:object
     exit_25: 0000/----/0/VM
     exit_26: 0002/0116/2 X1:int
     exit_27: 0007/0118/5 CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:unknown(zval_copy(rcx))
     exit_28: 0007/0123/5 CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:unknown(zval_copy(rcx))
     exit_29: 0007/0128/5/POLY(rax, rdi) CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:object
     exit_30: 0007/0133/5/VM CV0($context):object CV1($entry):undef CV2($cursor):undef CV3($newElement):undef X4:object
     exit_31: 0000/----/0/VM
     exit_32: 0003/0138/2 X1:int
     exit_33: 0006/0140/2/VM X1:int
     exit_34: 0008/0142/3 X0:int X1:int X2:float(-9.22337e+18)
     exit_35: 0008/0145/3/VM X0:int X1:int X2:int(rcx)
     exit_36: 0009/0148/3/VM X0:int X1:array X2:int(rcx)
     exit_37: 0009/0151/3 X0:int X1:array X2:int(rcx)
     exit_38: 0010/0154/3/FREE_OP1 X0:unknown(zval_copy(rdx)) X1:array X2:int(rcx)
     exit_39: 0010/0157/3/FREE_OP1 X0:unknown(zval_copy(rdx)) X1:array X2:int(rcx)
     exit_40: 0012/0160/5 CV0($context):object CV1($entry):object CV2($cursor):undef CV3($newElement):undef X4:object
     exit_41: 0011/0165/5/POLY(rax, rdi) CV0($context):object CV1($token):object CV2($el):undef X4:string
     exit_42: 0011/0170/5/VM CV0($context):object CV1($token):object CV2($el):undef X4:string
---- TRACE 50 compiled

     TRACE 36 exit 3 Rowbot\DOM\Parser\HTML\Tokenizer::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/Tokenizer.php:149
     TRACE 24 exit 9 Rowbot\DOM\Parser\HTML\Tokenizer::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/Tokenizer.php:310
     TRACE 32 exit 20 Rowbot\DOM\Parser\HTML\Tokenizer::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/Tokenizer.php:377
     TRACE 32 exit 20 Rowbot\DOM\Parser\HTML\Tokenizer::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/Tokenizer.php:377
     TRACE 32 exit 20 Rowbot\DOM\Parser\HTML\Tokenizer::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/Tokenizer.php:377
     TRACE 32 exit 5 Rowbot\DOM\Parser\HTML\Tokenizer::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/Tokenizer.php:355
     TRACE 20 exit 3 Rowbot\DOM\Parser\HTML\HTMLParser::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/HTMLParser.php:221
     TRACE 38 exit 9 Rowbot\DOM\Parser\HTML\TreeBuilder::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/TreeBuilder.php:91
     TRACE 19 exit 33 Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::getAppropriatePlaceForInsertingNode() /home/trevor/GitHub/PHPJS/src/Parser/HTML/InsertionMode/AbstractInsertionMode.php:363
     TRACE 39 exit 4 Rowbot\DOM\Parser\HTML\InsertionMode\InBodyInsertionMode::processToken() /home/trevor/GitHub/PHPJS/src/Parser/HTML/InsertionMode/InBodyInsertionMode.php:129
     TRACE 38 exit 9 Rowbot\DOM\Parser\HTML\TreeBuilder::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/TreeBuilder.php:91
     TRACE 19 exit 33 Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::getAppropriatePlaceForInsertingNode() /home/trevor/GitHub/PHPJS/src/Parser/HTML/InsertionMode/AbstractInsertionMode.php:363
     TRACE 38 exit 9 Rowbot\DOM\Parser\HTML\TreeBuilder::run() /home/trevor/GitHub/PHPJS/src/Parser/HTML/TreeBuilder.php:91
     TRACE 19 exit 33 Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::getAppropriatePlaceForInsertingNode() /home/trevor/GitHub/PHPJS/src/Parser/HTML/InsertionMode/AbstractInsertionMode.php:363
---- TRACE 51 start (side trace 19/33) Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::getAppropriatePlaceForInsertingNode() /home/trevor/GitHub/PHPJS/src/Parser/HTML/InsertionMode/AbstractInsertionMode.php:363
0100 T12 = FETCH_OBJ_R CV9($adjustedInsertionLocation) string("location") ; op1(object of class Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation) val(object)
0101 T13 = FETCH_CLASS_CONSTANT string("Rowbot\\DOM\\NodeInsertionLocation") string("BEFORE_END")
0102 T11 = IS_IDENTICAL T12 T13 ; op1(object of class Rowbot\DOM\NodeInsertionLocation) op2(object of class Rowbot\DOM\NodeInsertionLocation)
0103 ;JMPZ T11 0113
0104 V11 = NEW 2 string("Rowbot\\DOM\\Parser\\HTML\\AdjustedInsertionLocation")
     >init Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation::__construct
0105 CHECK_FUNC_ARG 1
0106 V13 = FETCH_OBJ_FUNC_ARG CV9($adjustedInsertionLocation) string("node") ; op1(object of class Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation) val(object)
0107 V12 = FETCH_OBJ_FUNC_ARG (ref) V13 string("content") ; op1(object of class Rowbot\DOM\Element\HTML\HTMLTemplateElement)
     >enter Rowbot\DOM\Element\HTML\HTMLTemplateElement::$content::get
0000  T0 = FETCH_OBJ_R THIS string("_content") ; val(object)
0001  VERIFY_RETURN_TYPE T0 ; op1(object of class Rowbot\DOM\DocumentFragment)
0002  RETURN T0 ; op1(object of class Rowbot\DOM\DocumentFragment)
     <back Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::getAppropriatePlaceForInsertingNode
0108 SEND_FUNC_ARG V12 1 ; op1(object of class Rowbot\DOM\DocumentFragment)
0109 T12 = FETCH_CLASS_CONSTANT string("Rowbot\\DOM\\NodeInsertionLocation") string("BEFORE_END")
0110 SEND_VAL_EX T12 2 ; op1(object of class Rowbot\DOM\NodeInsertionLocation)
0111 DO_FCALL
     >enter Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation::__construct
0000  CV0($node) = RECV 1
0001  CV1($location) = RECV 2
0002  ASSIGN_OBJ THIS string("node") ; op3(object) val(undef)
0003  ;OP_DATA CV0($node)
0004  ASSIGN_OBJ THIS string("location") ; op3(object) val(undef)
0005  ;OP_DATA CV1($location)
0006  RETURN null
     <back Rowbot\DOM\Parser\HTML\InsertionMode\AbstractInsertionMode::getAppropriatePlaceForInsertingNode
0112 ASSIGN CV9($adjustedInsertionLocation) V11 ; op1(object of class Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation) op2(object of class Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation)
0113 VERIFY_RETURN_TYPE CV9($adjustedInsertionLocation) ; op1(object of class Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation)
0114 RETURN CV9($adjustedInsertionLocation) ; op1(object of class Rowbot\DOM\Parser\HTML\AdjustedInsertionLocation)
---- TRACE 51 stop (return)
php: ./jit/zend_jit_trace.c:2399: zend_jit_trace_build_tssa: Assertion `&call->func->op_array == op_array' failed.
Aborted

Looking at the trace info, these are the code locations: https://github.com/TRowbotham/PHPDOM/blob/dev/src/Parser/HTML/TreeBuilder.php#L32 https://github.com/TRowbotham/PHPDOM/blob/dev/src/Parser/HTML/InsertionMode/InBodyInsertionMode.php#L55 https://github.com/TRowbotham/PHPDOM/blob/dev/src/Parser/HTML/InsertionMode/InBodyInsertionMode.php#L1589 https://github.com/TRowbotham/PHPDOM/blob/dev/src/Parser/HTML/InsertionMode/AbstractInsertionMode.php#L384 https://github.com/TRowbotham/PHPDOM/blob/dev/src/Parser/HTML/InsertionMode/AbstractInsertionMode.php#L281

I hit this assertion when running vendor/bin/phpunit tests/dom/nodes/DocumentFragmentGetElementByIdTest.php

PHP Version

master

Operating System

Ubuntu 22.04

dstogov commented 1 month ago

@iluuu1994 it seems this is related to property hooks. The assertion occurs because of the following "enter" record.

0107 V12 = FETCH_OBJ_FUNC_ARG (ref) V13 string("content") ; op1(object of class Rowbot\DOM\Element\HTML\HTMLTemplateElement)
     >enter Rowbot\DOM\Element\HTML\HTMLTemplateElement::$content::get
0000  T0 = FETCH_OBJ_R THIS string("_content") ; val(object)

Actually, the trace recorder shouldn't continue recording when magic handler is invoked. For regular __get() this is done through ZEND_ACC_CALL_VIA_TRAMPOLINE check and terminating recorder with ZEND_JIT_TRACE_STOP_TRAMPOLINE. Something similar should be done for property hooks.

iluuu1994 commented 1 month ago

@dstogov Thank you for the hint. Is this what you were suggesting? Since there's no reproducer, I couldn't verify it.

diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h
index ccc86a4834..2007f28e91 100644
--- a/ext/opcache/jit/zend_jit_internal.h
+++ b/ext/opcache/jit/zend_jit_internal.h
@@ -265,6 +265,7 @@ zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key);
    _(INNER_LOOP,        "inner loop")                     /* trace it */ \
    _(COMPILED_LOOP,     "compiled loop") \
    _(TRAMPOLINE,        "trampoline call") \
+   _(PROP_HOOK_CALL,    "property hook call") \
    _(BAD_FUNC,          "bad function call") \
    _(COMPILER_ERROR,    "JIT compilation error") \
    /* no recoverable error (blacklist immediately) */ \
diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c
index 2a7399c185..e9cdeeab98 100644
--- a/ext/opcache/jit/zend_jit_vm_helpers.c
+++ b/ext/opcache/jit/zend_jit_vm_helpers.c
@@ -503,6 +503,11 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend
            /* TODO: Can we continue recording ??? */
            return -1;
        }
+       /* Function is a property hook. */
+       if (func->common.prop_info) {
+           /* TODO: Can we continue recording ??? */
+           return -1;
+       }
        if (func->type == ZEND_INTERNAL_FUNCTION
         && (func->op_array.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE))) {
            return -1;
@@ -966,6 +971,12 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
                    break;
                }

+               if (EX(func)->op_array.prop_info) {
+                   /* TODO: Can we continue recording ??? */
+                   stop = ZEND_JIT_TRACE_STOP_PROP_HOOK_CALL;
+                   break;
+               }
+
                TRACE_RECORD(ZEND_JIT_TRACE_ENTER,
                    EX(return_value) != NULL ? ZEND_JIT_TRACE_RETURN_VALUE_USED : 0,
                    op_array);
@@ -1069,6 +1080,10 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
                    /* TODO: Can we continue recording ??? */
                    stop = ZEND_JIT_TRACE_STOP_BAD_FUNC;
                    break;
+               } else if (EX(call)->func->common.prop_info) {
+                   /* TODO: Can we continue recording ??? */
+                   stop = ZEND_JIT_TRACE_STOP_PROP_HOOK_CALL;
+                   break;
                }
                func = EX(call)->func;
                if (func->type == ZEND_INTERNAL_FUNCTION
TRowbotham commented 4 weeks ago

@iluuu1994 I tested your patch and it appears to fix the problem for me.

dstogov commented 2 weeks ago

The patch looks right to me. @iluuu1994 could you please merge it.

iluuu1994 commented 2 weeks ago

@dstogov Thank you very much for verifying!