Skip to content

Commit 303ec3c

Browse files
committed
Generate veneers to perform long jumps.
This makes symfony_demo app working with -d opcacge.jit=1205. (21 MB of JIT-ed code).
1 parent 9aa463c commit 303ec3c

File tree

2 files changed

+144
-1
lines changed

2 files changed

+144
-1
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ static bool zend_is_commutative(zend_uchar opcode)
209209
#if defined(__x86_64__) || defined(i386) || defined(ZEND_WIN32)
210210
#include "dynasm/dasm_x86.h"
211211
#elif defined(__aarch64__)
212+
static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int *b, uint32_t *cp, ptrdiff_t offset);
213+
#define DASM_ADD_VENEER zend_jit_add_veneer
212214
#include "dynasm/dasm_arm64.h"
213215
#endif
214216

@@ -408,6 +410,10 @@ static void *dasm_link_and_encode(dasm_State **dasm_state,
408410
return NULL;
409411
}
410412

413+
#ifdef __aarch64__
414+
dasm_venners_size = 0;
415+
#endif
416+
411417
ret = dasm_encode(dasm_state, *dasm_ptr);
412418
if (ret != DASM_S_OK) {
413419
#if ZEND_DEBUG
@@ -416,6 +422,10 @@ static void *dasm_link_and_encode(dasm_State **dasm_state,
416422
return NULL;
417423
}
418424

425+
#ifdef __aarch64__
426+
size += dasm_venners_size;
427+
#endif
428+
419429
entry = *dasm_ptr;
420430
*dasm_ptr = (void*)((char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(size, DASM_ALIGNMENT));
421431

@@ -4396,8 +4406,14 @@ ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, bool reattached)
43964406
return FAILURE;
43974407
}
43984408

4399-
/* save JIT buffer pos */
44004409
zend_jit_unprotect();
4410+
#ifdef __aarch64__
4411+
/* reserve space for global labels veneers */
4412+
dasm_labels_veneers = *dasm_ptr;
4413+
*dasm_ptr = (void**)*dasm_ptr + zend_lb_MAX;
4414+
memset(dasm_labels_veneers, 0, sizeof(void*) * zend_lb_MAX);
4415+
#endif
4416+
/* save JIT buffer pos */
44014417
dasm_ptr[1] = dasm_ptr[0];
44024418
zend_jit_protect();
44034419

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15017,6 +15017,133 @@ static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend
1501715017
return regset;
1501815018
}
1501915019

15020+
static size_t dasm_venners_size = 0;
15021+
void **dasm_labels_veneers = NULL;
15022+
15023+
static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int *b, uint32_t *cp, ptrdiff_t offset)
15024+
{
15025+
void *veneer;
15026+
ptrdiff_t na;
15027+
int n, m;
15028+
15029+
/* try to reuse veneers for global labels */
15030+
if ((ins >> 16) == DASM_REL_LG
15031+
&& *(b-1) < 0
15032+
&& dasm_labels_veneers[-*(b-1)]) {
15033+
15034+
veneer = dasm_labels_veneers[-*(b-1)];
15035+
na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4;
15036+
n = (int)na;
15037+
15038+
/* check if we can jump to veneer */
15039+
if ((ptrdiff_t)n != na) {
15040+
/* pass */
15041+
} else if (!(ins & 0xf800)) { /* B, BL */
15042+
if ((n & 3) == 0 && ((n+0x08000000) >> 28) == 0) {
15043+
return n;
15044+
}
15045+
} else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
15046+
if ((n & 3) == 0 && ((n+0x00100000) >> 21) == 0) {
15047+
return n;
15048+
}
15049+
} else if ((ins & 0x3000) == 0x2000) { /* ADR */
15050+
/* pass */
15051+
} else if ((ins & 0x3000) == 0x3000) { /* ADRP */
15052+
/* pass */
15053+
} else if ((ins & 0x1000)) { /* TBZ, TBNZ */
15054+
if ((n & 3) == 0 && ((n+0x00008000) >> 16) == 0) {
15055+
return n;
15056+
}
15057+
}
15058+
}
15059+
15060+
veneer = (char*)buffer + (Dst->codesize + dasm_venners_size);
15061+
15062+
if (veneer > dasm_end) {
15063+
return 0; /* jit_buffer_size overflow */
15064+
}
15065+
15066+
na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4;
15067+
n = (int)na;
15068+
15069+
/* check if we can jump to veneer */
15070+
if ((ptrdiff_t)n != na) {
15071+
ZEND_ASSERT(0);
15072+
return 0;
15073+
} else if (!(ins & 0xf800)) { /* B, BL */
15074+
if ((n & 3) != 0 || ((n+0x08000000) >> 28) != 0) {
15075+
ZEND_ASSERT(0);
15076+
return 0;
15077+
}
15078+
} else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */
15079+
if ((n & 3) != 0 || ((n+0x00100000) >> 21) != 0) {
15080+
ZEND_ASSERT(0);
15081+
return 0;
15082+
}
15083+
} else if ((ins & 0x3000) == 0x2000) { /* ADR */
15084+
ZEND_ASSERT(0);
15085+
return 0;
15086+
} else if ((ins & 0x3000) == 0x3000) { /* ADRP */
15087+
ZEND_ASSERT(0);
15088+
return 0;
15089+
} else if ((ins & 0x1000)) { /* TBZ, TBNZ */
15090+
if ((n & 3) != 0 || ((n+0x00008000) >> 16) != 0) {
15091+
ZEND_ASSERT(0);
15092+
return 0;
15093+
}
15094+
} else if ((ins & 0x8000)) { /* absolute */
15095+
ZEND_ASSERT(0);
15096+
return 0;
15097+
} else {
15098+
ZEND_ASSERT(0);
15099+
return 0;
15100+
}
15101+
15102+
// TODO: support for long veneers (above 128MB) ???
15103+
15104+
/* check if we can use B to jump from veneer */
15105+
na = (ptrdiff_t)cp + offset - (ptrdiff_t)veneer - 4;
15106+
m = (int)na;
15107+
if ((ptrdiff_t)m != na) {
15108+
ZEND_ASSERT(0);
15109+
return 0;
15110+
} else if ((m & 3) != 0 || ((m+0x08000000) >> 28) != 0) {
15111+
ZEND_ASSERT(0);
15112+
return 0;
15113+
}
15114+
15115+
/* generate B instruction */
15116+
*(uint32_t*)veneer = 0x14000000 | ((m >> 2) & 0x03ffffff);
15117+
dasm_venners_size += 4;
15118+
15119+
if ((ins >> 16) == DASM_REL_LG
15120+
&& *(b-1) < 0) {
15121+
/* reuse this veneer for the future jumps to global label */
15122+
dasm_labels_veneers[-*(b-1)] = veneer;
15123+
/* Dst->globals[*(b-1)] = veneer; */
15124+
15125+
#ifdef HAVE_DISASM
15126+
if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
15127+
const char *name = zend_jit_disasm_find_symbol((ptrdiff_t)cp + offset - 4, &offset);
15128+
15129+
if (name && !offset) {
15130+
if (strstr(name, "@veneer") == NULL) {
15131+
char *new_name;
15132+
15133+
zend_spprintf(&new_name, 0, "%s@veneer", name);
15134+
zend_jit_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4);
15135+
efree(new_name);
15136+
} else {
15137+
zend_jit_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4);
15138+
}
15139+
}
15140+
}
15141+
#endif
15142+
}
15143+
15144+
return n;
15145+
}
15146+
1502015147
#if defined(__clang__)
1502115148
# pragma clang diagnostic pop
1502215149
#endif

0 commit comments

Comments
 (0)