Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit afa4e02

Browse files
Implement frameless static calls
1 parent 1a2b370 commit afa4e02

File tree

7 files changed

+101
-8
lines changed

7 files changed

+101
-8
lines changed

‎Zend/Optimizer/zend_dump.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,10 @@ ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block
465465

466466
if (ZEND_OP_IS_FRAMELESS_ICALL(opline->opcode)) {
467467
zend_function *func = ZEND_FLF_FUNC(opline);
468-
fprintf(stderr, "(%s)", ZSTR_VAL(func->common.function_name));
468+
fprintf(stderr, "(%s%s%s)",
469+
func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
470+
func->common.scope ? "::" : "",
471+
ZSTR_VAL(func->common.function_name));
469472
}
470473

471474
if (ZEND_VM_EXT_NUM == (flags & ZEND_VM_EXT_MASK)) {

‎Zend/zend_compile.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@
5959

6060
#define FC(member) (CG(file_context).member)
6161

62+
#define ZEND_OP1_LITERAL(opline) (op_array)->literals[(opline)->op1.constant]
63+
#define ZEND_OP2_LITERAL(opline) (op_array)->literals[(opline)->op2.constant]
64+
#define literal_dtor(zv) do { \
65+
zval_ptr_dtor_nogc(zv); \
66+
ZVAL_NULL(zv); \
67+
} while (0)
68+
6269
typedef struct _zend_loop_var {
6370
uint8_t opcode;
6471
uint8_t var_type;
@@ -5333,6 +5340,7 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type
53335340
}
53345341
}
53355342

5343+
uint32_t init_opnum = get_next_op_number();
53365344
opline = get_next_op();
53375345
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
53385346

@@ -5375,6 +5383,21 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type
53755383
}
53765384
}
53775385

5386+
if (!(CG(compiler_options) & ZEND_COMPILE_NO_BUILTINS)
5387+
&& (fbc->type == ZEND_INTERNAL_FUNCTION)
5388+
&& zend_ast_is_list(args_ast)
5389+
&& !zend_args_contain_unpack_or_named(zend_ast_get_list(args_ast))) {
5390+
if (zend_compile_frameless_icall(result, zend_ast_get_list(args_ast), fbc, type) != (uint32_t)-1) {
5391+
/* Update opline in case it got invalidated. */
5392+
zend_op_array *op_array = CG(active_op_array);
5393+
opline = &op_array->opcodes[init_opnum];
5394+
literal_dtor(&ZEND_OP1_LITERAL(opline));
5395+
literal_dtor(&ZEND_OP2_LITERAL(opline));
5396+
MAKE_NOP(opline);
5397+
return;
5398+
}
5399+
}
5400+
53785401
zend_compile_call_common(result, args_ast, fbc, zend_ast_get_lineno(method_ast));
53795402
}
53805403
/* }}} */

‎build/gen_stub.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,10 @@ public function getDeclarationClassName(): string {
11181118
return implode('_', $this->className->getParts());
11191119
}
11201120

1121+
public function getDeclarationName(): string {
1122+
return "{$this->getDeclarationClassName()}_{$this->methodName}";
1123+
}
1124+
11211125
public function getDeclaration(): string {
11221126
return "ZEND_METHOD({$this->getDeclarationClassName()}, $this->methodName);\n";
11231127
}
@@ -1126,6 +1130,10 @@ public function getArgInfoName(): string {
11261130
return "arginfo_class_{$this->getDeclarationClassName()}_{$this->methodName}";
11271131
}
11281132

1133+
public function getFramelessFunctionInfosName(): string {
1134+
return "frameless_function_infos_{$this->className}_{$this->methodName}";
1135+
}
1136+
11291137
public function getMethodSynopsisFilename(): string
11301138
{
11311139
$parts = [...$this->className->getParts(), ltrim($this->methodName, '_')];
@@ -1396,12 +1404,12 @@ public function getFramelessDeclaration(FuncInfo $funcInfo): ?string {
13961404
}
13971405

13981406
foreach ($this->framelessFunctionInfos as $framelessFunctionInfo) {
1399-
$code .= "ZEND_FRAMELESS_FUNCTION({$this->name->getFunctionName()}, {$framelessFunctionInfo->arity});\n";
1407+
$code .= "ZEND_FRAMELESS_FUNCTION({$this->name->getDeclarationName()}, {$framelessFunctionInfo->arity});\n";
14001408
}
14011409

14021410
$code .= 'static const zend_frameless_function_info ' . $this->getFramelessFunctionInfosName() . "[] = {\n";
14031411
foreach ($this->framelessFunctionInfos as $framelessFunctionInfo) {
1404-
$code .= "\t{ ZEND_FRAMELESS_FUNCTION_NAME({$this->name->getFunctionName()}, {$framelessFunctionInfo->arity}), {$framelessFunctionInfo->arity} },\n";
1412+
$code .= "\t{ ZEND_FRAMELESS_FUNCTION_NAME({$this->name->getDeclarationName()}, {$framelessFunctionInfo->arity}), {$framelessFunctionInfo->arity} },\n";
14051413
}
14061414
$code .= "\t{ 0 },\n";
14071415
$code .= "};\n";
@@ -1427,10 +1435,10 @@ public function getFunctionEntry(): string {
14271435
$functionEntryCode = null;
14281436

14291437
if (!empty($this->framelessFunctionInfos)) {
1430-
if ($this->isMethod()) {
1431-
throw new Exception('Frameless methods are not supported yet');
1438+
if ($this->isMethod() && !($this->flags & Modifiers::STATIC)) {
1439+
throw new Exception('Frameless methods must be static');
14321440
}
1433-
if ($this->name->getNamespace()) {
1441+
if (!$this->isMethod() && $this->name->getNamespace()) {
14341442
throw new Exception('Namespaced direct calls to frameless functions are not supported yet');
14351443
}
14361444
if ($this->alias) {
@@ -5161,7 +5169,7 @@ function findEquivalentFuncInfo(array $generatedFuncInfos, FuncInfo $funcInfo):
51615169
function generateCodeWithConditions(
51625170
iterable $infos, string $separator, Closure $codeGenerator, ?string $parentCond = null): string {
51635171
$code = "";
5164-
5172+
51655173
// For combining the conditional blocks of the infos with the same condition
51665174
$openCondition = null;
51675175
foreach ($infos as $info) {

‎ext/zend_test/test.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,30 @@ static ZEND_METHOD(_ZendTestClass, takesUnionType)
11541154
RETURN_NULL();
11551155
}
11561156

1157+
static ZEND_METHOD(_ZendTestClass, framelessStaticMethod)
1158+
{
1159+
zend_long lhs, rhs;
1160+
1161+
ZEND_PARSE_PARAMETERS_START(2, 2)
1162+
Z_PARAM_LONG(lhs)
1163+
Z_PARAM_LONG(rhs)
1164+
ZEND_PARSE_PARAMETERS_END();
1165+
1166+
RETURN_LONG(lhs + rhs);
1167+
}
1168+
1169+
ZEND_FRAMELESS_FUNCTION(_ZendTestClass_framelessStaticMethod, 2)
1170+
{
1171+
zend_long lhs, rhs;
1172+
1173+
Z_FLF_PARAM_LONG(1, lhs);
1174+
Z_FLF_PARAM_LONG(2, rhs);
1175+
1176+
ZVAL_LONG(return_value, lhs + rhs);
1177+
1178+
flf_clean:;
1179+
}
1180+
11571181
// Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`.
11581182
//
11591183
// We need to generate it "manually" because gen_stubs.php does not support codegen for DNF types ATM.

‎ext/zend_test/test.stub.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ public function returnsThrowable(): Throwable {}
6868
static public function variadicTest(string|Iterator ...$elements) : static {}
6969

7070
public function takesUnionType(stdclass|Iterator $arg): void {}
71+
72+
/** @frameless-function {"arity": 2} */
73+
public static function framelessStaticMethod(int $lhs, int $rhs): int {}
7174
}
7275

7376
class _ZendTestMagicCall

‎ext/zend_test/test_arginfo.h

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Frameless static methods
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
var_dump(_ZendTestClass::framelessStaticMethod(42, 69));
9+
10+
?>
11+
--EXPECT--
12+
int(111)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /