Commit 54ec8c4873c for php
commit 54ec8c4873cabd43696b71c2b80622ee473ccccd
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Mon Nov 9 10:01:14 2026 -0500
Update IR
IR commit: 281a66a87aedc4444ca09f696b9b8e9dab89ad32
diff --git a/ext/opcache/jit/ir/dynasm/dasm_arm64.h b/ext/opcache/jit/ir/dynasm/dasm_arm64.h
index df8d5434d3a..2e22434eb5f 100644
--- a/ext/opcache/jit/ir/dynasm/dasm_arm64.h
+++ b/ext/opcache/jit/ir/dynasm/dasm_arm64.h
@@ -487,7 +487,7 @@ int dasm_encode(Dst_DECL, void *buffer)
}
break;
case DASM_REL_A: {
- ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n);
+ ptrdiff_t na = (ptrdiff_t)(((unsigned long long)(unsigned int)(*b++) << 32) | (unsigned int)n);
if ((ins & 0x3000) == 0x3000) { /* ADRP */
ins &= ~0x1000;
na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12);
diff --git a/ext/opcache/jit/ir/ir.h b/ext/opcache/jit/ir/ir.h
index 74481865e0f..8c2029c03be 100644
--- a/ext/opcache/jit/ir/ir.h
+++ b/ext/opcache/jit/ir/ir.h
@@ -904,11 +904,11 @@ IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val)
*p = val;
}
-IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val)
+IR_ALWAYS_INLINE uint32_t ir_insn_find_op_ex(const ir_insn *insn, ir_ref val, int start)
{
int i, n = insn->inputs_count;
- for (i = 1; i <= n; i++) {
+ for (i = start; i <= n; i++) {
if (ir_insn_op(insn, i) == val) {
return i;
}
@@ -916,6 +916,11 @@ IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val)
return 0;
}
+IR_ALWAYS_INLINE uint32_t ir_insn_find_op(const ir_insn *insn, ir_ref val)
+{
+ return ir_insn_find_op_ex(insn, val, 1);
+}
+
ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt);
diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc
index 965b3e9f745..5f7c3a42e8b 100644
--- a/ext/opcache/jit/ir/ir_aarch64.dasc
+++ b/ext/opcache/jit/ir/ir_aarch64.dasc
@@ -3599,33 +3599,33 @@ static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn)
IR_ASSERT(0);
case IR_SHL:
if (ir_type_size[type] == 1) {
- | and Rw(def_reg), Rw(op1_reg), #0xff
- | lsl Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+ | and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xff
+ | lsl Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
} else if (ir_type_size[type] == 2) {
- | and Rw(def_reg), Rw(op1_reg), #0xffff
- | lsl Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+ | and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xffff
+ | lsl Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
} else {
| ASM_REG_REG_REG_OP lsl, type, def_reg, op1_reg, op2_reg
}
break;
case IR_SHR:
if (ir_type_size[type] == 1) {
- | and Rw(def_reg), Rw(op1_reg), #0xff
- | lsr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+ | and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xff
+ | lsr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
} else if (ir_type_size[type] == 2) {
- | and Rw(def_reg), Rw(op1_reg), #0xffff
- | lsr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+ | and Rw(IR_REG_INT_TMP), Rw(op1_reg), #0xffff
+ | lsr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
} else {
| ASM_REG_REG_REG_OP lsr, type, def_reg, op1_reg, op2_reg
}
break;
case IR_SAR:
if (ir_type_size[type] == 1) {
- | sxtb Rw(def_reg), Rw(op1_reg)
- | asr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+ | sxtb Rw(IR_REG_INT_TMP), Rw(op1_reg)
+ | asr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
} else if (ir_type_size[type] == 2) {
- | sxth Rw(def_reg), Rw(op1_reg)
- | asr Rw(def_reg), Rw(def_reg), Rw(op2_reg)
+ | sxth Rw(IR_REG_INT_TMP), Rw(op1_reg)
+ | asr Rw(def_reg), Rw(IR_REG_INT_TMP), Rw(op2_reg)
} else {
| ASM_REG_REG_REG_OP asr, type, def_reg, op1_reg, op2_reg
}
@@ -6432,8 +6432,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
}
if (dst_reg != IR_REG_NONE) {
if (IR_IS_CONST_REF(arg) ||
- src_reg == IR_REG_NONE ||
- (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+ src_reg == IR_REG_NONE ||
+ (IR_REG_SPILLED(src_reg) &&
+ !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+ ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
/* delay CONST->REG and MEM->REG moves to third pass */
do_pass3 = 1;
} else {
@@ -6519,8 +6521,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
}
if (dst_reg != IR_REG_NONE) {
if (IR_IS_CONST_REF(arg) ||
- src_reg == IR_REG_NONE ||
- (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+ src_reg == IR_REG_NONE ||
+ (IR_REG_SPILLED(src_reg) &&
+ !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+ ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
if (IR_IS_CONST_REF(arg) && IR_IS_TYPE_INT(type)) {
if (ir_type_size[type] == 1) {
type = IR_ADDR;
@@ -10001,7 +10005,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
if (ctx->code_buffer) {
entry = ctx->code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
- if (size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)ctx->code_buffer->end || size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_CODE_MEM_OVERFLOW;
@@ -10144,7 +10148,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe
entry = code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
- if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
dasm_free(&dasm_state);
return NULL;
}
@@ -10314,7 +10318,7 @@ void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr)
entry = code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 4);
- if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
*size_ptr = size;
dasm_free(&dasm_state);
return NULL;
diff --git a/ext/opcache/jit/ir/ir_emit.c b/ext/opcache/jit/ir/ir_emit.c
index de6b53141a6..c53372d0ba3 100644
--- a/ext/opcache/jit/ir/ir_emit.c
+++ b/ext/opcache/jit/ir/ir_emit.c
@@ -968,30 +968,95 @@ static int ir_dessa_parallel_copy(ir_ctx *ctx, ir_dessa_copy *copies, int count,
}
/* finally we resolve remaining "windmill blades" - trees that set temporary registers */
- ir_bitset_copy(ready, todo, len);
- ir_bitset_difference(ready, srcs, len);
- while ((to = ir_bitset_pop_first(ready, len)) >= 0) {
- ir_bitset_excl(todo, to);
- type = types[to];
- from = pred[to];
-#ifdef IR_DEBUG
- /* If destionation is set, it can't be used as temporary anymore */
- if (to == tmp_reg) {
- tmp_reg = IR_REG_NONE;
- }
- if (to == tmp_fp_reg) {
- tmp_fp_reg = IR_REG_NONE;
+ if (tmp_reg != IR_REG_NONE && ir_bitset_in(todo, tmp_reg)) {
+ ir_mem tmp_spill_slot;
+ ir_type tmp_type;
+
+ ir_bitset_clear(ready, len);
+ to = tmp_reg;
+ tmp_type = types[to];
+ IR_MEM_VAL(tmp_spill_slot) = 0;
+ do {
+ ir_bitset_excl(todo, to);
+ type = types[to];
+ from = pred[to];
+ if (IR_IS_CONST_REF(from)) {
+ if (to >= IR_REG_NUM) {
+ /* Immediate to memory move inside a "blocked" blade requres an additional temporary register */
+ if (!IR_MEM_VAL(tmp_spill_slot)) {
+ /* Free a register, saving it in a temporary spill slot */
+ tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+ ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_reg);
+ }
+ }
+ ir_emit_dessa_move(ctx, mem_slots, type, to, from, tmp_reg, tmp_fp_reg);
+ } else {
+ int32_t r = loc[from];
+
+ /* Memory to memory move inside a "blocked" blade requres an additional temporary register */
+ if (to >= IR_REG_NUM && r >= IR_REG_NUM) {
+ if (!IR_MEM_VAL(tmp_spill_slot)) {
+ /* Free a register, saving it in a temporary spill slot */
+ tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+ ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_reg);
+ }
+ }
+ ir_emit_dessa_move(ctx, mem_slots, type, to, r, tmp_reg, tmp_fp_reg);
+ loc[from] = to;
+ if (from == r && ir_bitset_in(todo, from)) {
+ ir_bitset_incl(ready, from);
+ }
+ }
+ } while ((to = ir_bitset_pop_first(ready, len)) >= 0);
+
+ if (IR_MEM_VAL(tmp_spill_slot)) {
+ ir_emit_load_mem(ctx, tmp_type, tmp_reg, tmp_spill_slot);
}
-#endif
- if (IR_IS_CONST_REF(from)) {
- ir_emit_dessa_move(ctx, mem_slots, type, to, from, tmp_reg, tmp_fp_reg);
- } else {
- int32_t r = loc[from];
- ir_emit_dessa_move(ctx, mem_slots, type, to, r, tmp_reg, tmp_fp_reg);
- loc[from] = to;
- if (from == r && ir_bitset_in(todo, from)) {
- ir_bitset_incl(ready, from);
+ }
+
+ if (tmp_fp_reg != IR_REG_NONE && ir_bitset_in(todo, tmp_fp_reg)) {
+ ir_mem tmp_spill_slot;
+ ir_type tmp_type;
+
+ ir_bitset_clear(ready, len);
+ to = tmp_fp_reg;
+ tmp_type = types[to];
+ IR_MEM_VAL(tmp_spill_slot) = 0;
+ do {
+ ir_bitset_excl(todo, to);
+ type = types[to];
+ from = pred[to];
+ if (IR_IS_CONST_REF(from)) {
+ /* Immediate to memory move inside a "blocked" blade requres an additional temporary register */
+ if (to >= IR_REG_NUM) {
+ if (!IR_MEM_VAL(tmp_spill_slot)) {
+ /* Free a register, saving it in a temporary spill slot */
+ tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+ ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_fp_reg);
+ }
+ }
+ ir_emit_dessa_move(ctx, mem_slots, type, to, from, tmp_reg, tmp_fp_reg);
+ } else {
+ int32_t r = loc[from];
+
+ /* Memory to memory move inside a "blocked" blade requres an additional temporary register */
+ if (to >= IR_REG_NUM && r >= IR_REG_NUM) {
+ if (!IR_MEM_VAL(tmp_spill_slot)) {
+ /* Free a register, saving it in a temporary spill slot */
+ tmp_spill_slot = IR_MEM_BO(IR_REG_STACK_POINTER, -16);
+ ir_emit_store_mem(ctx, tmp_type, tmp_spill_slot, tmp_fp_reg);
+ }
+ }
+ ir_emit_dessa_move(ctx, mem_slots, type, to, r, tmp_reg, tmp_fp_reg);
+ loc[from] = to;
+ if (from == r && ir_bitset_in(todo, from)) {
+ ir_bitset_incl(ready, from);
+ }
}
+ } while ((to = ir_bitset_pop_first(ready, len)) >= 0);
+
+ if (IR_MEM_VAL(tmp_spill_slot)) {
+ ir_emit_load_mem(ctx, tmp_type, tmp_fp_reg, tmp_spill_slot);
}
}
diff --git a/ext/opcache/jit/ir/ir_fold.h b/ext/opcache/jit/ir/ir_fold.h
index c8292191b5e..962668b9bc6 100644
--- a/ext/opcache/jit/ir/ir_fold.h
+++ b/ext/opcache/jit/ir/ir_fold.h
@@ -4275,7 +4275,7 @@ IR_FOLD(ULE(_, _))
IR_FOLD(UGT(_, _))
{
if (op1 == op2) {
- if (IR_IS_TYPE_SCALAR(IR_OPT_TYPE(opt))) {
+ if (IR_IS_TYPE_INT(op1_insn->type)) {
/* a >= a => true (two low bits are differ) */
IR_FOLD_BOOL((opt ^ (opt >> 1)) & 1);
}
diff --git a/ext/opcache/jit/ir/ir_private.h b/ext/opcache/jit/ir/ir_private.h
index 9f91fbfba9f..5bca99a50c9 100644
--- a/ext/opcache/jit/ir/ir_private.h
+++ b/ext/opcache/jit/ir/ir_private.h
@@ -901,7 +901,7 @@ extern const uint8_t ir_type_size[IR_LAST_TYPE];
IR_ALWAYS_INLINE ir_type ir_make_vector_type(ir_type base, uint8_t length)
{
- IR_ASSERT(IR_IS_TYPE_SCALAR(base) && length > 0 && length <= 64 && (length & (length - 1)) == 0);
+ IR_ASSERT(IR_IS_TYPE_SCALAR(base) && base != IR_ADDR && length > 0 && length <= 64 && (length & (length - 1)) == 0);
if (base == IR_CHAR) {
base = IR_I8;
diff --git a/ext/opcache/jit/ir/ir_ra.c b/ext/opcache/jit/ir/ir_ra.c
index f8d418d0614..886413ecf84 100644
--- a/ext/opcache/jit/ir/ir_ra.c
+++ b/ext/opcache/jit/ir/ir_ra.c
@@ -837,7 +837,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
ival = ctx->live_intervals[v];
if (UNEXPECTED(!ival)) {
/* Dead PHI */
- ival = ir_add_live_range(ctx, v, IR_DEF_LIVE_POS_FROM_REF(ref), IR_USE_LIVE_POS_FROM_REF(ref));
+ ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), IR_SAVE_LIVE_POS_FROM_REF(ref));
}
ival->type = insn->type;
ir_add_use(ctx, ival, 0, IR_DEF_LIVE_POS_FROM_REF(ref), IR_REG_NONE, IR_USE_SHOULD_BE_IN_REG, 0);
@@ -1554,7 +1554,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
ival = ctx->live_intervals[v];
if (UNEXPECTED(!ival)) {
/* Dead PHI */
- ival = ir_add_live_range(ctx, v, IR_DEF_LIVE_POS_FROM_REF(ref), IR_USE_LIVE_POS_FROM_REF(ref));
+ ival = ir_add_live_range(ctx, v, IR_START_LIVE_POS_FROM_REF(bb->start), IR_SAVE_LIVE_POS_FROM_REF(ref));
}
ival->type = insn->type;
ir_add_use(ctx, ival, 0, IR_DEF_LIVE_POS_FROM_REF(ref), IR_REG_NONE, IR_USE_SHOULD_BE_IN_REG, 0);
diff --git a/ext/opcache/jit/ir/ir_sccp.c b/ext/opcache/jit/ir/ir_sccp.c
index 2ca202add5e..8818a667f6f 100644
--- a/ext/opcache/jit/ir/ir_sccp.c
+++ b/ext/opcache/jit/ir/ir_sccp.c
@@ -2228,6 +2228,10 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref
const ir_insn *use_insn = &ctx->ir_base[use];
if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) {
+ if (op == IR_ZEXT && use_insn->op >= IR_LT && use_insn->op <= IR_GT) {
+ /* Zero extension may reset the sign bit and change the result of signed comparison */
+ return 0;
+ }
if (use_insn->op1 == phi_ref) {
if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op2].type)) {
return 0;
@@ -2267,6 +2271,10 @@ static bool ir_try_promote_induction_var_ext(ir_ctx *ctx, ir_ref ext_ref, ir_ref
const ir_insn *use_insn = &ctx->ir_base[use];
if (use_insn->op >= IR_EQ && use_insn->op <= IR_UGT) {
+ if (op == IR_ZEXT && use_insn->op >= IR_LT && use_insn->op <= IR_GT) {
+ /* Zero extension may reset the sign bit and change the result of signed comparison */
+ return 0;
+ }
if (use_insn->op1 == op_ref) {
if (IR_IS_TYPE_SIGNED(type) != IR_IS_TYPE_SIGNED(ctx->ir_base[use_insn->op2].type)) {
return 0;
diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc
index 463be9e750d..aa4e6e3da52 100644
--- a/ext/opcache/jit/ir/ir_x86.dasc
+++ b/ext/opcache/jit/ir/ir_x86.dasc
@@ -7731,6 +7731,15 @@ static void ir_emit_shift(ir_ctx *ctx, ir_ref def, ir_insn *insn)
IR_ASSERT(def_reg != IR_REG_NONE && def_reg != IR_REG_RCX);
if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) {
op1_reg = IR_REG_NUM(op1_reg);
+ /* in case op1_reg and op2_reg are the same - op2 should be moved to %rcx, then op1 loaded from spill slot */
+ if (op2_reg != IR_REG_NONE && op1_reg == IR_REG_NUM(op2_reg) && insn->op1 != insn->op2) {
+ if (IR_REG_SPILLED(op2_reg)) {
+ ir_emit_load(ctx, type, IR_REG_RCX, insn->op2);
+ } else if (op2_reg != IR_REG_RCX) {
+ ir_emit_mov(ctx, type, IR_REG_RCX, op2_reg);
+ }
+ op2_reg = IR_REG_RCX;
+ }
ir_emit_load(ctx, type, op1_reg, insn->op1);
}
if (op2_reg != IR_REG_NONE && IR_REG_SPILLED(op2_reg)) {
@@ -13467,8 +13476,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
}
if (dst_reg != IR_REG_NONE) {
if (IR_IS_CONST_REF(arg) ||
- src_reg == IR_REG_NONE ||
- (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+ src_reg == IR_REG_NONE ||
+ (IR_REG_SPILLED(src_reg) &&
+ !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+ ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
/* delay CONST->REG and MEM->REG moves to third pass */
do_pass3 = 1;
} else {
@@ -13600,8 +13611,10 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, const i
}
if (dst_reg != IR_REG_NONE) {
if (IR_IS_CONST_REF(arg) ||
- src_reg == IR_REG_NONE ||
- (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)))) {
+ src_reg == IR_REG_NONE ||
+ (IR_REG_SPILLED(src_reg) &&
+ !IR_REGSET_IN(cc->preserved_regs, IR_REG_NUM(src_reg)) &&
+ ir_insn_find_op_ex(insn, arg, j + 1) == 0)) {
if (IR_IS_TYPE_INT(type)) {
if (IR_IS_CONST_REF(arg)) {
if (type == IR_I8 || type == IR_I16) {
@@ -27566,7 +27579,7 @@ next_block:;
if (ctx->code_buffer) {
entry = ctx->code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), required_alignment);
- if (size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)ctx->code_buffer->end || size > (size_t)((char*)ctx->code_buffer->end - (char*)entry)) {
dasm_free(&data.dasm_state);
ctx->data = NULL;
ctx->status = IR_ERROR_CODE_MEM_OVERFLOW;
@@ -27650,7 +27663,7 @@ next_block:;
ir_mem_flush(entry, size);
-#if defined(__GNUC__)
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
if ((ctx->flags & IR_GEN_CACHE_DEMOTE) && (ctx->mflags & IR_X86_CLDEMOTE)) {
uintptr_t start = (uintptr_t)entry;
uintptr_t p = (uintptr_t)start & ~0x3F;
@@ -27706,7 +27719,7 @@ const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_pe
entry = code_buffer->pos;
entry = (void*)IR_ALIGNED_SIZE(((size_t)(entry)), 16);
- if (size > (size_t)((char*)code_buffer->end - (char*)entry)) {
+ if ((char*)entry > (char*)code_buffer->end || size > (size_t)((char*)code_buffer->end - (char*)entry)) {
dasm_free(&dasm_state);
return NULL;
}