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 7be62b7

Browse files
Implement frameless static calls
1 parent 17187c4 commit 7be62b7

File tree

7 files changed

+102
-8
lines changed

7 files changed

+102
-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: 24 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;
@@ -5329,6 +5336,7 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type
53295336
}
53305337
}
53315338

5339+
uint32_t init_opnum = get_next_op_number();
53325340
opline = get_next_op();
53335341
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
53345342

@@ -5371,6 +5379,22 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type
53715379
}
53725380
}
53735381

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

‎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) {
@@ -5175,7 +5183,7 @@ function findEquivalentFuncInfo(array $generatedFuncInfos, FuncInfo $funcInfo):
51755183
function generateCodeWithConditions(
51765184
iterable $infos, string $separator, Closure $codeGenerator, ?string $parentCond = null): string {
51775185
$code = "";
5178-
5186+
51795187
// For combining the conditional blocks of the infos with the same condition
51805188
$openCondition = null;
51815189
foreach ($infos as $info) {

‎ext/zend_test/test.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,30 @@ static ZEND_METHOD(_ZendTestClass, takesUnionType)
11621162
RETURN_NULL();
11631163
}
11641164

1165+
static ZEND_METHOD(_ZendTestClass, framelessStaticMethod)
1166+
{
1167+
zend_long lhs, rhs;
1168+
1169+
ZEND_PARSE_PARAMETERS_START(2, 2)
1170+
Z_PARAM_LONG(lhs)
1171+
Z_PARAM_LONG(rhs)
1172+
ZEND_PARSE_PARAMETERS_END();
1173+
1174+
RETURN_LONG(lhs + rhs);
1175+
}
1176+
1177+
ZEND_FRAMELESS_FUNCTION(_ZendTestClass_framelessStaticMethod, 2)
1178+
{
1179+
zend_long lhs, rhs;
1180+
1181+
Z_FLF_PARAM_LONG(1, lhs);
1182+
Z_FLF_PARAM_LONG(2, rhs);
1183+
1184+
ZVAL_LONG(return_value, lhs + rhs);
1185+
1186+
flf_clean:;
1187+
}
1188+
11651189
// Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`.
11661190
//
11671191
// 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 によって変換されたページ (->オリジナル) /