Skip to content

Commit 8c1b63c

Browse files
committed
[jit] Introduce Opcache\Jit attribute to replace @jit
Instead of @jit in the docblock you can now use the <<Opcache\Jit>> attribute. In addition this attribute allows you to disable the JIT for a specific function as well with <<Opcache\Jit(false)>>. Another behavior change is that the Opcache\Jit attribute has precedence over any other trigger as well. This means you can allow to force JIT in profiling triggers or disable JIT for a function regardless of trigger.
1 parent bd1e66b commit 8c1b63c

File tree

5 files changed

+133
-37
lines changed

5 files changed

+133
-37
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "Zend/zend_exceptions.h"
2424
#include "Zend/zend_constants.h"
2525
#include "zend_smart_str.h"
26+
#include "Zend/zend_attributes.h"
2627
#include "jit/zend_jit.h"
2728

2829
#ifdef HAVE_JIT
@@ -3233,21 +3234,38 @@ static int zend_jit_setup_hot_counters(zend_op_array *op_array)
32333234
return SUCCESS;
32343235
}
32353236

3237+
static int zend_disable_jit(const zend_op_array *op_array)
3238+
{
3239+
zend_attribute *jit = zend_get_attribute_str(op_array->attributes, "opcache\\jit", sizeof("opcache\\jit")-1, 0);
3240+
3241+
if (jit == NULL || jit->argc == 0) {
3242+
return 0;
3243+
}
3244+
3245+
if (Z_TYPE(jit->argv[0]) == IS_FALSE) {
3246+
return 1;
3247+
}
3248+
3249+
return 0;
3250+
}
3251+
32363252
static int zend_needs_manual_jit(const zend_op_array *op_array)
32373253
{
3238-
if (op_array->doc_comment) {
3239-
const char *s = ZSTR_VAL(op_array->doc_comment);
3240-
const char *p = strstr(s, "@jit");
3254+
zend_attribute *jit = zend_get_attribute_str(op_array->attributes, "opcache\\jit", sizeof("opcache\\jit")-1, 0);
32413255

3242-
if (p) {
3243-
size_t l = ZSTR_LEN(op_array->doc_comment);
3256+
if (jit == NULL) {
3257+
return 0;
3258+
}
32443259

3245-
if ((p == s + 3 || *(p-1) <= ' ') &&
3246-
(p + 6 == s + l || *(p+4) <= ' ')) {
3247-
return 1;
3248-
}
3260+
if (jit->argc == 0) {
3261+
return 1;
3262+
} else if (jit->argc == 1) {
3263+
// todo: evaluate "trueish"?
3264+
if (Z_TYPE(jit->argv[0]) == IS_TRUE) {
3265+
return 1;
32493266
}
32503267
}
3268+
32513269
return 0;
32523270
}
32533271

@@ -3259,6 +3277,14 @@ ZEND_EXT_API int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
32593277
return FAILURE;
32603278
}
32613279

3280+
if (zend_disable_jit(op_array) == 1) {
3281+
return SUCCESS;
3282+
}
3283+
3284+
if (zend_needs_manual_jit(op_array) == 1) {
3285+
return zend_real_jit_func(op_array, script, NULL);
3286+
}
3287+
32623288
if (zend_jit_trigger == ZEND_JIT_ON_FIRST_EXEC) {
32633289
zend_op *opline = op_array->opcodes;
32643290

@@ -3294,12 +3320,6 @@ ZEND_EXT_API int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
32943320
return zend_jit_setup_hot_trace_counters(op_array);
32953321
} else if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD) {
32963322
return zend_real_jit_func(op_array, script, NULL);
3297-
} else if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT) {
3298-
if (zend_needs_manual_jit(op_array)) {
3299-
return zend_real_jit_func(op_array, script, NULL);
3300-
} else {
3301-
return SUCCESS;
3302-
}
33033323
} else {
33043324
ZEND_ASSERT(0);
33053325
}
@@ -3335,21 +3355,8 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33353355
goto jit_failure;
33363356
}
33373357
}
3338-
} else if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD ||
3339-
zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT) {
3358+
} else if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD || zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE) {
33403359

3341-
if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT) {
3342-
int do_jit = 0;
3343-
for (i = 0; i < call_graph.op_arrays_count; i++) {
3344-
if (zend_needs_manual_jit(call_graph.op_arrays[i])) {
3345-
do_jit = 1;
3346-
break;
3347-
}
3348-
}
3349-
if (!do_jit) {
3350-
goto jit_failure;
3351-
}
3352-
}
33533360
for (i = 0; i < call_graph.op_arrays_count; i++) {
33543361
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
33553362
if (info) {
@@ -3371,10 +3378,12 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33713378
}
33723379

33733380
for (i = 0; i < call_graph.op_arrays_count; i++) {
3374-
if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT &&
3375-
!zend_needs_manual_jit(call_graph.op_arrays[i])) {
3381+
if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD && zend_disable_jit(call_graph.op_arrays[i])) {
3382+
continue;
3383+
} else if (zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE && !zend_needs_manual_jit(call_graph.op_arrays[i])) {
33763384
continue;
33773385
}
3386+
33783387
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
33793388
if (info) {
33803389
if (zend_jit_op_array_analyze2(call_graph.op_arrays[i], script, &info->ssa) != SUCCESS) {
@@ -3386,10 +3395,12 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33863395

33873396
if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_SSA) {
33883397
for (i = 0; i < call_graph.op_arrays_count; i++) {
3389-
if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT &&
3390-
!zend_needs_manual_jit(call_graph.op_arrays[i])) {
3398+
if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD && zend_disable_jit(call_graph.op_arrays[i])) {
3399+
continue;
3400+
} else if (zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE && !zend_needs_manual_jit(call_graph.op_arrays[i])) {
33913401
continue;
33923402
}
3403+
33933404
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
33943405
if (info) {
33953406
zend_dump_op_array(call_graph.op_arrays[i], ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", &info->ssa);
@@ -3398,10 +3409,12 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33983409
}
33993410

34003411
for (i = 0; i < call_graph.op_arrays_count; i++) {
3401-
if (zend_jit_trigger == ZEND_JIT_ON_DOC_COMMENT &&
3402-
!zend_needs_manual_jit(call_graph.op_arrays[i])) {
3412+
if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD && zend_disable_jit(call_graph.op_arrays[i])) {
3413+
continue;
3414+
} else if (zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE && !zend_needs_manual_jit(call_graph.op_arrays[i])) {
34033415
continue;
34043416
}
3417+
34053418
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
34063419
if (info) {
34073420
if (zend_jit(call_graph.op_arrays[i], &info->ssa, NULL) != SUCCESS) {
@@ -3577,7 +3590,6 @@ static void zend_jit_globals_ctor(zend_jit_globals *jit_globals)
35773590
ZEND_EXT_API int zend_jit_startup(zend_long jit, void *buf, size_t size, zend_bool reattached)
35783591
{
35793592
int ret;
3580-
35813593
#ifdef ZTS
35823594
zend_jit_globals_id = ts_allocate_id(&zend_jit_globals_id, sizeof(zend_jit_globals), (ts_allocate_ctor) zend_jit_globals_ctor, NULL);
35833595
#else

ext/opcache/jit/zend_jit.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#define ZEND_JIT_ON_FIRST_EXEC 1
3333
#define ZEND_JIT_ON_PROF_REQUEST 2 /* compile the most frequently caled on first request functions */
3434
#define ZEND_JIT_ON_HOT_COUNTERS 3 /* compile functions after N calls or loop iterations */
35-
#define ZEND_JIT_ON_DOC_COMMENT 4 /* compile functions with "@jit" tag in doc-comments */
35+
#define ZEND_JIT_ON_ATTRIBUTE 4 /* compile functions with "Opcache\Jit" attribute */
3636
#define ZEND_JIT_ON_HOT_TRACE 5 /* trace functions after N calls or loop iterations */
3737

3838
#define ZEND_JIT_TRIGGER(n) (((n) / 10) % 10)
@@ -129,4 +129,6 @@ struct _zend_lifetime_interval {
129129
zend_lifetime_interval *list_next;
130130
};
131131

132+
zend_class_entry *zend_ce_opcache_jit_attribute;
133+
132134
#endif /* HAVE_JIT_H */
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
Opcache\Jit Attribute
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=64
8+
opcache.jit=1245
9+
opcache.jit_debug=257
10+
--SKIPIF--
11+
<?php require_once('skipif.inc'); ?>
12+
--FILE--
13+
<?php
14+
15+
<<Opcache\Jit(true)>>
16+
function test() {
17+
return 1234;
18+
}
19+
function test2() {
20+
}
21+
22+
test2();
23+
test();
24+
?>
25+
--EXPECTF--
26+
JIT$test: ; (%s)%A
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Opcache\Jit Attribute disables function
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=64
8+
opcache.jit=1205
9+
opcache.jit_debug=257
10+
--SKIPIF--
11+
<?php require_once('skipif.inc'); ?>
12+
--FILE--
13+
<?php
14+
15+
<<Opcache\Jit(false)>>
16+
function test() {
17+
return 1234;
18+
}
19+
function test2() {
20+
}
21+
22+
test();
23+
test2();
24+
?>
25+
--EXPECTF--
26+
JIT$%s: ; (%s)
27+
sub $0x10, %s
28+
add $0x10, %s
29+
mov $ZEND_RETURN_SPEC_CONST_LABEL, %s
30+
jmp *%s
31+
32+
JIT$test2: ; (%s)%A

ext/opcache/zend_accelerator_module.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "zend_virtual_cwd.h"
3232
#include "ext/standard/info.h"
3333
#include "ext/standard/php_filestat.h"
34+
#include "Zend/zend_attributes.h"
3435
#include "opcache_arginfo.h"
3536

3637
#if HAVE_JIT
@@ -360,12 +361,35 @@ static ZEND_NAMED_FUNCTION(accel_is_readable)
360361
}
361362
}
362363

364+
void zend_jit_validate_opcache_attribute(zend_attribute *jit, int target)
365+
{
366+
if (target != ZEND_ATTRIBUTE_TARGET_METHOD && target != ZEND_ATTRIBUTE_TARGET_FUNCTION) {
367+
zend_error(E_COMPILE_ERROR, "<<Opcache\\Jit>> attribute can only be declared on methods or functions.");
368+
}
369+
370+
if (jit->argc > 1) {
371+
zend_error(E_COMPILE_ERROR, "<<Opcache\\Jit>> requires zero or one argument, %d arguments given.", jit->argc);
372+
}
373+
374+
if (jit->argc == 1 && Z_TYPE(jit->argv[0]) != IS_TRUE && Z_TYPE(jit->argv[0]) != IS_FALSE) {
375+
zend_error(E_COMPILE_ERROR, "<<Opcache\\Jit>> first argument $enabled must be a boolean.");
376+
}
377+
}
378+
363379
static ZEND_MINIT_FUNCTION(zend_accelerator)
364380
{
365381
(void)type; /* keep the compiler happy */
382+
zend_class_entry ce;
366383

367384
REGISTER_INI_ENTRIES();
368385

386+
INIT_NS_CLASS_ENTRY(ce, "Opcache", "Jit", NULL);
387+
zend_ce_opcache_jit_attribute = zend_register_internal_class(&ce);
388+
zend_ce_opcache_jit_attribute->ce_flags |= ZEND_ACC_FINAL;
389+
390+
zend_compiler_attribute_register(zend_ce_opcache_jit_attribute, &zend_jit_validate_opcache_attribute);
391+
392+
369393
return SUCCESS;
370394
}
371395

0 commit comments

Comments
 (0)