@@ -345,6 +345,15 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
345
345
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), _type); \
346
346
} while (0)
347
347
348
+ #define ADD_OP_GUARD (_var , _op_type ) do { \
349
+ if (_var >= 0 && _op_type != IS_UNKNOWN) { \
350
+ zend_ssa_var_info *info = &ssa_var_info[_var]; \
351
+ if ((info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << _op_type)) { \
352
+ info->type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex(_op_type, info->type); \
353
+ } \
354
+ } \
355
+ } while (0)
356
+
348
357
#define CHECK_OP_TRACE_TYPE (_var , _ssa_var , op_info , op_type ) do { \
349
358
if (op_type != IS_UNKNOWN) { \
350
359
if ((op_info & MAY_BE_GUARD) != 0 \
@@ -365,6 +374,12 @@ static zend_always_inline uint32_t zend_jit_trace_type_to_info(zend_uchar type)
365
374
} \
366
375
} while (0)
367
376
377
+ #define ADD_OP1_TRACE_GUARD () \
378
+ ADD_OP_GUARD(tssa->ops[idx].op1_use, op1_type)
379
+ #define ADD_OP2_TRACE_GUARD () \
380
+ ADD_OP_GUARD(tssa->ops[idx].op2_use, op2_type)
381
+ #define ADD_OP1_DATA_TRACE_GUARD () \
382
+ ADD_OP_GUARD(tssa->ops[idx+1].op1_use, op3_type)
368
383
#define CHECK_OP1_TRACE_TYPE () \
369
384
CHECK_OP_TRACE_TYPE(opline->op1.var, ssa_op->op1_use, op1_info, op1_type)
370
385
#define CHECK_OP2_TRACE_TYPE () \
@@ -1294,15 +1309,43 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
1294
1309
}
1295
1310
1296
1311
switch (opline -> opcode ) {
1312
+ case ZEND_ASSIGN_OP :
1313
+ if (opline -> extended_value == ZEND_POW
1314
+ || opline -> extended_value == ZEND_DIV ) {
1315
+ // TODO: check for division by zero ???
1316
+ break ;
1317
+ }
1318
+ if (opline -> op1_type != IS_CV || opline -> result_type != IS_UNUSED ) {
1319
+ break ;
1320
+ }
1321
+ ADD_OP1_TRACE_GUARD ();
1322
+ ADD_OP2_TRACE_GUARD ();
1323
+ break ;
1297
1324
case ZEND_ASSIGN_DIM_OP :
1325
+ if (opline -> extended_value == ZEND_POW
1326
+ || opline -> extended_value == ZEND_DIV ) {
1327
+ // TODO: check for division by zero ???
1328
+ break ;
1329
+ }
1330
+ if (opline -> result_type != IS_UNUSED ) {
1331
+ break ;
1332
+ }
1333
+ /* break missing intentionally */
1298
1334
case ZEND_ASSIGN_DIM :
1299
- if (tssa -> ops [idx + 1 ].op1_use >= 0 && op3_type != IS_UNKNOWN ) {
1300
- zend_ssa_var_info * info = & ssa_var_info [ssa_ops [idx + 1 ].op1_use ];
1301
- if ((info -> type & (MAY_BE_ANY |MAY_BE_UNDEF )) != (1 << op3_type )) {
1302
- info -> type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex (op3_type , info -> type );
1303
- }
1335
+ if (opline -> op1_type != IS_CV ) {
1336
+ break ;
1304
1337
}
1338
+ ADD_OP1_DATA_TRACE_GUARD ();
1305
1339
/* break missing intentionally */
1340
+ case ZEND_IS_EQUAL :
1341
+ case ZEND_IS_NOT_EQUAL :
1342
+ case ZEND_IS_SMALLER :
1343
+ case ZEND_IS_SMALLER_OR_EQUAL :
1344
+ case ZEND_CASE :
1345
+ case ZEND_IS_IDENTICAL :
1346
+ case ZEND_IS_NOT_IDENTICAL :
1347
+ case ZEND_FETCH_DIM_R :
1348
+ case ZEND_FETCH_DIM_IS :
1306
1349
case ZEND_BW_OR :
1307
1350
case ZEND_BW_AND :
1308
1351
case ZEND_BW_XOR :
@@ -1315,76 +1358,71 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
1315
1358
// case ZEND_DIV: // TODO: check for division by zero ???
1316
1359
case ZEND_CONCAT :
1317
1360
case ZEND_FAST_CONCAT :
1318
- case ZEND_ASSIGN_OP :
1319
- case ZEND_IS_EQUAL :
1320
- case ZEND_IS_NOT_EQUAL :
1321
- case ZEND_IS_SMALLER :
1322
- case ZEND_IS_SMALLER_OR_EQUAL :
1323
- case ZEND_CASE :
1324
- case ZEND_IS_IDENTICAL :
1325
- case ZEND_IS_NOT_IDENTICAL :
1326
- case ZEND_FETCH_DIM_R :
1327
- case ZEND_FETCH_DIM_IS :
1328
- case ZEND_ISSET_ISEMPTY_DIM_OBJ :
1329
- if (tssa -> ops [idx ].op2_use >= 0 && op2_type != IS_UNKNOWN ) {
1330
- zend_ssa_var_info * info = & ssa_var_info [ssa_ops [idx ].op2_use ];
1331
- if ((info -> type & (MAY_BE_ANY |MAY_BE_UNDEF )) != (1 << op2_type )) {
1332
- info -> type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex (op2_type , info -> type );
1333
- }
1334
- }
1361
+ ADD_OP2_TRACE_GUARD ();
1335
1362
/* break missing intentionally */
1363
+ case ZEND_ECHO :
1364
+ case ZEND_STRLEN :
1365
+ case ZEND_QM_ASSIGN :
1366
+ ADD_OP1_TRACE_GUARD ();
1367
+ break ;
1336
1368
case ZEND_PRE_INC :
1337
1369
case ZEND_PRE_DEC :
1338
1370
case ZEND_POST_INC :
1339
1371
case ZEND_POST_DEC :
1340
- case ZEND_QM_ASSIGN :
1341
- case ZEND_BOOL :
1342
- case ZEND_BOOL_NOT :
1372
+ if (opline -> op1_type != IS_CV ) {
1373
+ break ;
1374
+ }
1375
+ ADD_OP1_TRACE_GUARD ();
1376
+ break ;
1377
+ case ZEND_ASSIGN :
1378
+ if (opline -> op1_type != IS_CV ) {
1379
+ break ;
1380
+ }
1381
+ ADD_OP2_TRACE_GUARD ();
1382
+ break ;
1383
+ case ZEND_CAST :
1384
+ if (opline -> extended_value != op1_type ) {
1385
+ break ;
1386
+ }
1387
+ ADD_OP1_TRACE_GUARD ();
1388
+ break ;
1343
1389
case ZEND_JMPZ :
1344
1390
case ZEND_JMPNZ :
1391
+ if (/*opline > op_array->opcodes + ssa->cfg.blocks[b].start && ??? */
1392
+ opline -> op1_type == IS_TMP_VAR &&
1393
+ ((opline - 1 )-> result_type & (IS_SMART_BRANCH_JMPZ |IS_SMART_BRANCH_JMPNZ )) != 0 ) {
1394
+ /* smart branch */
1395
+ break ;
1396
+ }
1397
+ /* break missing intentionally */
1345
1398
case ZEND_JMPZNZ :
1346
1399
case ZEND_JMPZ_EX :
1347
1400
case ZEND_JMPNZ_EX :
1348
- case ZEND_ECHO :
1349
- case ZEND_STRLEN :
1350
- if (tssa -> ops [idx ].op1_use >= 0 && op1_type != IS_UNKNOWN ) {
1351
- zend_ssa_var_info * info = & ssa_var_info [ssa_ops [idx ].op1_use ];
1352
- if ((info -> type & (MAY_BE_ANY |MAY_BE_UNDEF )) != (1 << op1_type )) {
1353
- info -> type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex (op1_type , info -> type );
1354
- }
1355
- }
1401
+ case ZEND_BOOL :
1402
+ case ZEND_BOOL_NOT :
1403
+ ADD_OP1_TRACE_GUARD ();
1356
1404
break ;
1357
- case ZEND_CAST :
1358
- if (tssa -> ops [idx ].op1_use >= 0 && op1_type != IS_UNKNOWN ) {
1359
- if (opline -> extended_value == op1_type ) {
1360
- zend_ssa_var_info * info = & ssa_var_info [ssa_ops [idx ].op1_use ];
1361
- if ((info -> type & (MAY_BE_ANY |MAY_BE_UNDEF )) != (1 << op1_type )) {
1362
- info -> type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex (op1_type , info -> type );
1363
- }
1364
- }
1405
+ case ZEND_ISSET_ISEMPTY_DIM_OBJ :
1406
+ if ((opline -> extended_value & ZEND_ISEMPTY )) {
1407
+ // TODO: support for empty() ???
1408
+ break ;
1365
1409
}
1410
+ ADD_OP1_TRACE_GUARD ();
1411
+ ADD_OP2_TRACE_GUARD ();
1366
1412
break ;
1367
- case ZEND_ASSIGN :
1368
- if (tssa -> ops [idx ].op2_use >= 0 && op2_type != IS_UNKNOWN ) {
1369
- zend_ssa_var_info * info = & ssa_var_info [ssa_ops [idx ].op2_use ];
1370
- if ((info -> type & (MAY_BE_ANY |MAY_BE_UNDEF )) != (1 << op2_type )) {
1371
- info -> type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex (op2_type , info -> type );
1372
- }
1413
+ case ZEND_SEND_VAL_EX :
1414
+ case ZEND_SEND_VAR_EX :
1415
+ case ZEND_SEND_VAR_NO_REF_EX :
1416
+ if (opline -> op2 .num > MAX_ARG_FLAG_NUM ) {
1417
+ goto propagate_arg ;
1373
1418
}
1374
- break ;
1419
+ /* break missing intentionally */
1375
1420
case ZEND_SEND_VAL :
1376
- case ZEND_SEND_VAL_EX :
1377
1421
case ZEND_SEND_VAR :
1378
- case ZEND_SEND_VAR_EX :
1379
1422
case ZEND_SEND_VAR_NO_REF :
1380
- case ZEND_SEND_VAR_NO_REF_EX :
1381
1423
case ZEND_SEND_FUNC_ARG :
1382
- if (tssa -> ops [idx ].op1_use >= 0 && op1_type != IS_UNKNOWN ) {
1383
- zend_ssa_var_info * info = & ssa_var_info [ssa_ops [idx ].op1_use ];
1384
- if ((info -> type & (MAY_BE_ANY |MAY_BE_UNDEF )) != (1 << op1_type )) {
1385
- info -> type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex (op1_type , info -> type );
1386
- }
1387
- }
1424
+ ADD_OP1_TRACE_GUARD ();
1425
+ propagate_arg :
1388
1426
/* Propagate argument type */
1389
1427
if (frame -> call
1390
1428
&& frame -> call -> func -> type == ZEND_USER_FUNCTION
@@ -1422,12 +1460,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
1422
1460
}
1423
1461
break ;
1424
1462
case ZEND_RETURN :
1425
- if (tssa -> ops [idx ].op1_use >= 0 && op1_type != IS_UNKNOWN ) {
1426
- zend_ssa_var_info * info = & ssa_var_info [ssa_ops [idx ].op1_use ];
1427
- if ((info -> type & (MAY_BE_ANY |MAY_BE_UNDEF )) != (1 << op1_type )) {
1428
- info -> type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex (op1_type , info -> type );
1429
- }
1430
- }
1463
+ ADD_OP1_TRACE_GUARD ();
1431
1464
/* Propagate return value types */
1432
1465
if (opline -> op1_type == IS_UNUSED ) {
1433
1466
return_value_info .type = MAY_BE_NULL ;
0 commit comments