Skip to content

Commit d3d7fce

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 d3d7fce

File tree

5 files changed

+135
-26
lines changed

5 files changed

+135
-26
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 50 additions & 25 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,10 +3355,9 @@ 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) {
3360+
if (zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE) {
33423361
int do_jit = 0;
33433362
for (i = 0; i < call_graph.op_arrays_count; i++) {
33443363
if (zend_needs_manual_jit(call_graph.op_arrays[i])) {
@@ -3350,6 +3369,7 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33503369
goto jit_failure;
33513370
}
33523371
}
3372+
33533373
for (i = 0; i < call_graph.op_arrays_count; i++) {
33543374
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
33553375
if (info) {
@@ -3371,10 +3391,12 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33713391
}
33723392

33733393
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])) {
3394+
if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD && zend_disable_jit(call_graph.op_arrays[i])) {
3395+
continue;
3396+
} else if (zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE && !zend_needs_manual_jit(call_graph.op_arrays[i])) {
33763397
continue;
33773398
}
3399+
33783400
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
33793401
if (info) {
33803402
if (zend_jit_op_array_analyze2(call_graph.op_arrays[i], script, &info->ssa) != SUCCESS) {
@@ -3386,10 +3408,12 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33863408

33873409
if (ZCG(accel_directives).jit_debug & ZEND_JIT_DEBUG_SSA) {
33883410
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])) {
3411+
if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD && zend_disable_jit(call_graph.op_arrays[i])) {
3412+
continue;
3413+
} else if (zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE && !zend_needs_manual_jit(call_graph.op_arrays[i])) {
33913414
continue;
33923415
}
3416+
33933417
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
33943418
if (info) {
33953419
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 +3422,12 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
33983422
}
33993423

34003424
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])) {
3425+
if (zend_jit_trigger == ZEND_JIT_ON_SCRIPT_LOAD && zend_disable_jit(call_graph.op_arrays[i])) {
3426+
continue;
3427+
} else if (zend_jit_trigger == ZEND_JIT_ON_ATTRIBUTE && !zend_needs_manual_jit(call_graph.op_arrays[i])) {
34033428
continue;
34043429
}
3430+
34053431
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
34063432
if (info) {
34073433
if (zend_jit(call_graph.op_arrays[i], &info->ssa, NULL) != SUCCESS) {
@@ -3577,7 +3603,6 @@ static void zend_jit_globals_ctor(zend_jit_globals *jit_globals)
35773603
ZEND_EXT_API int zend_jit_startup(zend_long jit, void *buf, size_t size, zend_bool reattached)
35783604
{
35793605
int ret;
3580-
35813606
#ifdef ZTS
35823607
zend_jit_globals_id = ts_allocate_id(&zend_jit_globals_id, sizeof(zend_jit_globals), (ts_allocate_ctor) zend_jit_globals_ctor, NULL);
35833608
#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)