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 9a64646

Browse files
Implement frameless static calls
1 parent 99f72fa commit 9a64646

File tree

7 files changed

+101
-7
lines changed

7 files changed

+101
-7
lines changed

‎Zend/Optimizer/zend_dump.c

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

480480
if (ZEND_OP_IS_FRAMELESS_ICALL(opline->opcode)) {
481481
zend_function *func = ZEND_FLF_FUNC(opline);
482-
fprintf(stderr, "(%s)", ZSTR_VAL(func->common.function_name));
482+
fprintf(stderr, "(%s%s%s)",
483+
func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
484+
func->common.scope ? "::" : "",
485+
ZSTR_VAL(func->common.function_name));
483486
}
484487

485488
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;
@@ -5336,6 +5343,7 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type
53365343
}
53375344
}
53385345

5346+
uint32_t init_opnum = get_next_op_number();
53395347
opline = get_next_op();
53405348
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
53415349

@@ -5378,6 +5386,22 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type
53785386
}
53795387
}
53805388

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

‎build/gen_stub.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,10 @@ public function getDeclarationClassName(): string {
10601060
return implode('_', $this->className->getParts());
10611061
}
10621062

1063+
public function getDeclarationName(): string {
1064+
return "{$this->getDeclarationClassName()}_{$this->methodName}";
1065+
}
1066+
10631067
public function getDeclaration(): string {
10641068
return "ZEND_METHOD({$this->getDeclarationClassName()}, $this->methodName);\n";
10651069
}
@@ -1068,6 +1072,10 @@ public function getArgInfoName(): string {
10681072
return "arginfo_class_{$this->getDeclarationClassName()}_{$this->methodName}";
10691073
}
10701074

1075+
public function getFramelessFunctionInfosName(): string {
1076+
return "frameless_function_infos_{$this->className}_{$this->methodName}";
1077+
}
1078+
10711079
public function getMethodSynopsisFilename(): string
10721080
{
10731081
$parts = [...$this->className->getParts(), ltrim($this->methodName, '_')];
@@ -1331,12 +1339,12 @@ public function getFramelessDeclaration(): ?string {
13311339
}
13321340

13331341
foreach ($this->framelessFunctionInfos as $framelessFunctionInfo) {
1334-
$code .= "ZEND_FRAMELESS_FUNCTION({$this->name->getFunctionName()}, {$framelessFunctionInfo->arity});\n";
1342+
$code .= "ZEND_FRAMELESS_FUNCTION({$this->name->getDeclarationName()}, {$framelessFunctionInfo->arity});\n";
13351343
}
13361344

13371345
$code .= 'static const zend_frameless_function_info ' . $this->getFramelessFunctionInfosName() . "[] = {\n";
13381346
foreach ($this->framelessFunctionInfos as $framelessFunctionInfo) {
1339-
$code .= "\t{ ZEND_FRAMELESS_FUNCTION_NAME({$this->name->getFunctionName()}, {$framelessFunctionInfo->arity}), {$framelessFunctionInfo->arity} },\n";
1347+
$code .= "\t{ ZEND_FRAMELESS_FUNCTION_NAME({$this->name->getDeclarationName()}, {$framelessFunctionInfo->arity}), {$framelessFunctionInfo->arity} },\n";
13401348
}
13411349
$code .= "\t{ 0 },\n";
13421350
$code .= "};\n";
@@ -1362,10 +1370,10 @@ public function getFunctionEntry(): string {
13621370
$functionEntryCode = null;
13631371

13641372
if (!empty($this->framelessFunctionInfos)) {
1365-
if ($this->isMethod()) {
1366-
throw new Exception('Frameless methods are not supported yet');
1373+
if ($this->isMethod() && !($this->flags & Modifiers::STATIC)) {
1374+
throw new Exception('Frameless methods must be static');
13671375
}
1368-
if ($this->name->getNamespace()) {
1376+
if (!$this->isMethod() && $this->name->getNamespace()) {
13691377
throw new Exception('Namespaced direct calls to frameless functions are not supported yet');
13701378
}
13711379
if ($this->alias) {

‎ext/zend_test/test.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,30 @@ static ZEND_METHOD(_ZendTestClass, takesUnionType)
11691169
RETURN_NULL();
11701170
}
11711171

1172+
static ZEND_METHOD(_ZendTestClass, framelessStaticMethod)
1173+
{
1174+
zend_long lhs, rhs;
1175+
1176+
ZEND_PARSE_PARAMETERS_START(2, 2)
1177+
Z_PARAM_LONG(lhs)
1178+
Z_PARAM_LONG(rhs)
1179+
ZEND_PARSE_PARAMETERS_END();
1180+
1181+
RETURN_LONG(lhs + rhs);
1182+
}
1183+
1184+
ZEND_FRAMELESS_FUNCTION(_ZendTestClass_framelessStaticMethod, 2)
1185+
{
1186+
zend_long lhs, rhs;
1187+
1188+
Z_FLF_PARAM_LONG(1, lhs);
1189+
Z_FLF_PARAM_LONG(2, rhs);
1190+
1191+
ZVAL_LONG(return_value, lhs + rhs);
1192+
1193+
flf_clean:;
1194+
}
1195+
11721196
// Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`.
11731197
//
11741198
// 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
@@ -69,6 +69,9 @@ public function returnsThrowable(): Throwable {}
6969
static public function variadicTest(string|Iterator ...$elements) : static {}
7070

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

7477
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 によって変換されたページ (->オリジナル) /