# Does PHP ever stack allocate?

- Thread: https://externals.io/message/112707
- Original archive: https://news-web.php.net/php.internals/112707
- Started by olleharstedt@gmail.com on 2021-01-01T21:18:10+00:00
- Messages: 8
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #112707 — olleharstedt@gmail.com — 2021-01-01T21:18:10+00:00

URL: https://externals.io/message/112707#112707

Or is everything reference counted with heap allocation? Since PHP has
escape analysis, this could be used to use the stack instead, and kill the
memory when the scope ends. If PHP uses the stack, can this be seen in the
opcode?

This stackoverflow thread does not really answer my question.

https://stackoverflow.com/questions/24223249/stack-and-heap-in-php#:~:text=In%20static%20typed%20languages%20all,known%20until%20the%20run%20time
.

Olle

---

## #112730 — Sara Golemon — 2021-01-03T16:15:10+00:00

URL: https://externals.io/message/112707#112730 · In reply to: #112707

> Or is everything reference counted with heap allocation? Since PHP has
> escape analysis, this could be used to use the stack instead, and kill the
> memory when the scope ends. If PHP uses the stack, can this be seen in the
> opcode?
>
>
Well, you're not going to like this answer, but.... yes and no.

A single PHP call frame holds a block of storage space for (among other
things) all* local variables.  This can be thought of analogously to "the
stack" as it's used by native applications.  Basic scalars (null, bool,
int, float) sit in this space with no additional pointers to anywhere.
Non-scalars use pointers to elsewhere in the heap to store the actual
payload.  This isn't unique to PHP, as these structures have runtime
determined size and thus can't** be stack allocated.

There's further asterii below all of those statements, but that's the
high-level generalized answer to your question as posed.

The implied question you asked is actually handled using another
mechanism.  PHP's internals have two separate memory allocation pools.
"Persistent" memory allocation, which creates blocks of memory for the
lifetime of the process, and "Engine" memory allocation, which are bulk
de-allocated*** at the end of every request (after relevant
destructors have fired).

-Sara

* All variables which are explicitly references as $foo (excluding
auto-globals).  ${'bar'} and $$baz style references to locals are special
and require their own separate conversation.
** C's alloca() and similar techniques in other languages can reserve
dynamic amounts of stack space, but let's ignore that power-move for the
sake of this argument.
*** Deallocated from the request handler's point of view, though the
runtime's memory manager (usually) doesn't give it back to the OS
immediately, since it's likely to be used by the next request anyway.

---

## #112731 — olleharstedt@gmail.com — 2021-01-03T16:37:50+00:00

URL: https://externals.io/message/112707#112731 · In reply to: #112730

2021-01-03 16:15 GMT, Sara Golemon <pollita@php.net>:
> On Fri, Jan 1, 2021 at 3:18 PM Olle Härstedt <olleharstedt@gmail.com>
> wrote:
>
> > […]
> Well, you're not going to like this answer, but.... yes and no.
>
> A single PHP call frame holds a block of storage space for (among other
> things) all* local variables.  This can be thought of analogously to "the
> stack" as it's used by native applications.  Basic scalars (null, bool,
> int, float) sit in this space with no additional pointers to anywhere.
> Non-scalars use pointers to elsewhere in the heap to store the actual
> payload.  This isn't unique to PHP, as these structures have runtime
> determined size and thus can't** be stack allocated.
>
> There's further asterii below all of those statements, but that's the
> high-level generalized answer to your question as posed.
>
> The implied question you asked is actually handled using another
> mechanism.  PHP's internals have two separate memory allocation pools.
> "Persistent" memory allocation, which creates blocks of memory for the
> lifetime of the process, and "Engine" memory allocation, which are bulk
> de-allocated*** at the end of every request (after relevant
> destructors have fired).
>
> -Sara
>
> * All variables which are explicitly references as $foo (excluding
> auto-globals).  ${'bar'} and $$baz style references to locals are special
> and require their own separate conversation.
> ** C's alloca() and similar techniques in other languages can reserve
> dynamic amounts of stack space, but let's ignore that power-move for the
> sake of this argument.
> *** Deallocated from the request handler's point of view, though the
> runtime's memory manager (usually) doesn't give it back to the OS
> immediately, since it's likely to be used by the next request anyway.
>

Thanks Sara! I realize I should have been more precise: Can PHP
allocate non-reference counted memory that automatically is freed when
leaving scope, similar to what Go does with escape analysis?

Article describing the Go mechanism:
https://segment.com/blog/allocation-efficiency-in-high-performance-go-services/

Olle

---

## #112734 — tyson andre — 2021-01-03T17:43:24+00:00

URL: https://externals.io/message/112707#112734 · In reply to: #112731

Hi Olle,

> Thanks Sara! I realize I should have been more precise: Can PHP
> allocate non-reference counted memory that automatically is freed when
> leaving scope, similar to what Go does with escape analysis?
>
> Article describing the Go mechanism:
> https://segment.com/blog/allocation-efficiency-in-high-performance-go-services/

Could you give some concrete examples of what type of code you're talking about?
As Sara Golemon said, scalars (null, bool, int, float) are allocated on a php call frame,
and the call frames go on a stack. That stack is separate from the C stack, but still a stack

The call frame is "freed" when leaving scope - i.e. that part of the stack will be reused on subsequent calls.

> A single PHP call frame holds a block of storage space for (among other
> things) all* local variables.  This can be thought of analogously to "the
> stack" as it's used by native applications.  Basic scalars (null, bool,
> int, float) sit in this space with no additional pointers to anywhere.
> Non-scalars use pointers to elsewhere in the heap to store the actual
> payload.  This isn't unique to PHP, as these structures have runtime
> determined size and thus can't** be stack allocated.

https://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html may help if you want to learn more about what the PHP VM currently does

> So what’s the difference between TMP and VAR? Not much.
> The distinction was inherited from PHP 5, where TMPs were VM stack allocated,
> while VARs were heap allocated. In PHP 7 all variables are stack allocated.
> As such, nowadays the main difference between TMPs and VARs is that only the latter are allowed to contain REFERENCEs
> (this allows us to elide DEREFs on TMPs). Furthermore VARs may hold two types of special values,
> namely class entries and INDIRECT values. The latter are used to handle non-trivial assignments.

-Tyson

---

## #112735 — Sara Golemon — 2021-01-03T17:49:52+00:00

URL: https://externals.io/message/112707#112735 · In reply to: #112731

On Sun, Jan 3, 2021 at 10:37 AM Olle Härstedt <olleharstedt@gmail.com>
wrote:
> Thanks Sara! I realize I should have been more precise: Can PHP
> allocate non-reference counted memory that automatically is freed when
> leaving scope, similar to what Go does with escape analysis?
>

It seems like you're conflating userspace variables and their underlying
data storage mechanisms and while the two are related and have naturally
similar semantics, they're not really the same thing and trying to
generically talk about both at the same time is only going to add to
confusion.

If you're talking about userspace variables... Yeah.  They're scope bound
and destructed/freed on scope exit.  Nearly every language does some form
of this because to not do so would be leaky and awful.

If you're talking about internal memory allocators, then the idea of
"automatically freed" is a red-herring.  It's an illusion created by some
languages to cover up the quite explicit mechanisms in place to handle data
lifetimes.  PHP does its form of this as well using a combination of stack
and heap allocators as appropriate.

-Sara

---

## #112745 — olleharstedt@gmail.com — 2021-01-04T10:53:12+00:00

URL: https://externals.io/message/112707#112745 · In reply to: #112734

2021-01-03 17:43 GMT, tyson andre <tysonandre775@hotmail.com>:
> Hi Olle,
>
> > […]
>
> Could you give some concrete examples of what type of code you're talking
> about?
> As Sara Golemon said, scalars (null, bool, int, float) are allocated on a
> php call frame,
> and the call frames go on a stack. That stack is separate from the C stack,
> but still a stack
>
> The call frame is "freed" when leaving scope - i.e. that part of the stack
> will be reused on subsequent calls.

Sure. Consider the following trivial snippet:

```php
class Point {
  public $x;
  public $y;
}
function foo() {
  $p = new Point();
  return $p->x + $p->y;
}
```

Since we know the lifetime of $p, we don't have to ref count it.
Escape analysis helps with checking lifetimes and to remove needles
ref counting (and heap allocations in compiled languages). There is a
file in php-src for this:
https://github.com/php/php-src/blob/master/ext/opcache/Optimizer/escape_analysis.c

My question was about how this functionality is used.

> > […]
>
> https://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html may help if
> you want to learn more about what the PHP VM currently does

Nice link, thanks!

Olle

---

## #112758 — Nikita Popov — 2021-01-05T10:51:33+00:00

URL: https://externals.io/message/112707#112758 · In reply to: #112745

On Mon, Jan 4, 2021 at 11:53 AM Olle Härstedt <olleharstedt@gmail.com>
wrote:

> 2021-01-03 17:43 GMT, tyson andre <tysonandre775@hotmail.com>:
> > […]
> https://segment.com/blog/allocation-efficiency-in-high-performance-go-services/
> > […]
> stack,
> > […]
> stack
> > […]
>
> Sure. Consider the following trivial snippet:
>
> ```php
> class Point {
>   public $x;
>   public $y;
> }
> function foo() {
>   $p = new Point();
>   return $p->x + $p->y;
> }
> ```
>
> Since we know the lifetime of $p, we don't have to ref count it.
> Escape analysis helps with checking lifetimes and to remove needles
> ref counting (and heap allocations in compiled languages). There is a
> file in php-src for this:
>
> https://github.com/php/php-src/blob/master/ext/opcache/Optimizer/escape_analysis.c
>
> My question was about how this functionality is used.
>

I believe the escape analysis is currently only used as part of SCCP to
perform constant folding on objects. For example, we would be able to fold
the following function down to "return 3;":

function foo() {
    $p = new Point();
    $p->x = 1;
    $p->y = 2;
    return $p->x + $p->y;
}

However, I think the optimization you have in mind is more along the lines
of dropping the object and storing its properties as local variables
instead.

I don't think the escape analysis is particularly useful outside of
stdClass possibly, as it will bail on classes from different files, and
classes with constructors anyway.

Nikita

---

## #112820 — olleharstedt@gmail.com — 2021-01-09T16:25:26+00:00

URL: https://externals.io/message/112707#112820 · In reply to: #112758

2021-01-05 10:51 GMT, Nikita Popov <nikita.ppv@gmail.com>:
> On Mon, Jan 4, 2021 at 11:53 AM Olle Härstedt <olleharstedt@gmail.com>
> wrote:
>
> > […]
>
> I believe the escape analysis is currently only used as part of SCCP to
> perform constant folding on objects. For example, we would be able to fold
> the following function down to "return 3;":
>
> function foo() {
>     $p = new Point();
>     $p->x = 1;
>     $p->y = 2;
>     return $p->x + $p->y;
> }
>
> However, I think the optimization you have in mind is more along the lines
> of dropping the object and storing its properties as local variables
> instead.

Hm, this is called scalar replacement, I think.

Olle
