Skip to content

Commit

Permalink
Allocate a HashTable for each scope stack frame
Browse files Browse the repository at this point in the history
  • Loading branch information
jbboehr committed Feb 12, 2024
1 parent 79d9163 commit 0693fae
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 19 deletions.
6 changes: 5 additions & 1 deletion php_vyrtue.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ zend_ast *vyrtue_context_node_stack_top(struct vyrtue_context *ctx);

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
zend_ast *vyrtue_context_scope_stack_top(struct vyrtue_context *ctx);
zend_ast *vyrtue_context_scope_stack_top_ast(struct vyrtue_context *ctx);

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
HashTable *vyrtue_context_scope_stack_top_ht(struct vyrtue_context *ctx);

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
Expand Down
21 changes: 17 additions & 4 deletions src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,27 @@ zend_arena *vyrtue_context_get_arena(struct vyrtue_context *ctx)

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
zend_ast *vyrtue_context_node_stack_top(struct vyrtue_context *ctx)
zend_ast *vyrtue_context_scope_stack_top_ast(struct vyrtue_context *ctx)
{
return vyrtue_context_stack_top(&ctx->node_stack);
struct vyrtue_context_stack_frame *frame = vyrtue_context_stack_top(&ctx->scope_stack);
if (UNEXPECTED(NULL == frame)) {
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: stack underflow");
}
ZEND_ASSERT(frame->ast != NULL);
return frame->ast;
}

VYRTUE_PUBLIC
VYRTUE_ATTR_NONNULL_ALL
zend_ast *vyrtue_context_scope_stack_top(struct vyrtue_context *ctx)
HashTable *vyrtue_context_scope_stack_top_ht(struct vyrtue_context *ctx)
{
return vyrtue_context_stack_top(&ctx->scope_stack);
struct vyrtue_context_stack_frame *frame = vyrtue_context_stack_top(&ctx->scope_stack);
if (UNEXPECTED(NULL == frame)) {
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: stack underflow");
}
if (frame->ht == NULL) {
frame->ht = zend_arena_calloc(&ctx->arena, 1, sizeof(HashTable));
zend_hash_init(frame->ht, 8, NULL, NULL, 0);
}
return frame->ht;
}
37 changes: 25 additions & 12 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@
#include <Zend/zend_errors.h>
#include "php_vyrtue.h"

#define VYRTUE_STACK_SIZE 256
#define VYRTUE_STACK_SIZE 128

struct vyrtue_context_stack_frame
{
zend_ast *ast;
HashTable *ht;
};

struct vyrtue_context_stack
{
size_t i;
zend_ast *data[VYRTUE_STACK_SIZE];
struct vyrtue_context_stack_frame data[VYRTUE_STACK_SIZE];
};

struct vyrtue_context
Expand All @@ -49,25 +55,32 @@ struct vyrtue_context
VYRTUE_ATTR_NONNULL_ALL
static inline void vyrtue_context_stack_push(struct vyrtue_context_stack *stack, zend_ast *ast)
{
stack->data[stack->i] = ast;
if (UNEXPECTED(stack->i) >= VYRTUE_STACK_SIZE) {
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: stack overflow");
}

stack->data[stack->i].ast = ast;
stack->i++;
}

VYRTUE_ATTR_NONNULL_ALL
static inline void vyrtue_context_stack_pop(struct vyrtue_context_stack *stack, zend_ast *ast)
{
if (UNEXPECTED(stack->i <= 0)) {
zend_error(E_WARNING, "vyrtue: stack underflow");
return;
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: stack underflow");
}

stack->i--;

if (UNEXPECTED(ast != stack->data[stack->i])) {
zend_error(E_WARNING, "vyrtue: stack pop mismatch");
if (UNEXPECTED(ast != stack->data[stack->i].ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: stack pop mismatch");
}

stack->data[stack->i] = NULL;
stack->data[stack->i].ast = NULL;

if (stack->data[stack->i].ht) {
zend_hash_destroy(stack->data[stack->i].ht);
}
}

VYRTUE_ATTR_NONNULL_ALL
Expand All @@ -77,14 +90,14 @@ static inline size_t vyrtue_context_stack_count(struct vyrtue_context_stack *sta
}

VYRTUE_ATTR_NONNULL_ALL
static inline zend_ast *vyrtue_context_stack_top(struct vyrtue_context_stack *stack)
VYRTUE_ATTR_RETURNS_NONNULL
static inline struct vyrtue_context_stack_frame *vyrtue_context_stack_top(struct vyrtue_context_stack *stack)
{
if (UNEXPECTED(stack->i <= 0)) {
zend_error(E_WARNING, "vyrtue: stack underflow");
return NULL;
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: stack underflow");
}

return stack->data[stack->i - 1];
return &stack->data[stack->i - 1];
}

#endif
23 changes: 23 additions & 0 deletions src/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,68 @@

#include "php_vyrtue.h"

static inline void run_common_asserts(struct vyrtue_context *ctx)
{
if (NULL == vyrtue_context_scope_stack_top_ht(ctx)) {
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: debug failed to fetch stack ht");
}

if (NULL == vyrtue_context_scope_stack_top_ast(ctx)) {
zend_error_noreturn(E_COMPILE_ERROR, "vyrtue: debug failed to fetch scope stack ast");
}
}

static zend_ast *vyrtue_debug_sample_replacement_enter(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "entering sample function\n");

run_common_asserts(ctx);

return zend_ast_create_zval_from_long(12345);
}

static zend_ast *vyrtue_debug_sample_replacement_leave(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "leaving sample function\n");

run_common_asserts(ctx);

return NULL;
}

static zend_ast *vyrtue_debug_sample_function_enter(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "entering sample function\n");

run_common_asserts(ctx);

return NULL;
}

static zend_ast *vyrtue_debug_sample_function_leave(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "leaving sample function\n");

run_common_asserts(ctx);

return NULL;
}

static zend_ast *vyrtue_debug_sample_attribute_enter(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "entering sample attribute\n");

run_common_asserts(ctx);

return NULL;
}

static zend_ast *vyrtue_debug_sample_attribute_leave(zend_ast *ast, struct vyrtue_context *ctx)
{
fprintf(stderr, "leaving sample attribute\n");

run_common_asserts(ctx);

return NULL;
}

Expand Down
7 changes: 5 additions & 2 deletions src/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -512,12 +512,15 @@ void vyrtue_ast_process_file(zend_ast *ast)
.arena = zend_arena_create(8 * 1024),
};

vyrtue_context_stack_push(&ctx.scope_stack, ast);

zend_ast *replace = vyrtue_ast_walk(ast, &ctx);
if (replace != NULL) {
zend_throw_exception(zend_ce_parse_error, "vyrtue visitor attempted to replace the root AST node which is unsupported", 0);
return;
zend_throw_exception(zend_ce_parse_error, "vyrtue: visitor attempted to replace the root AST node which is unsupported", 0);
}

vyrtue_context_stack_pop(&ctx.scope_stack, ast);

#ifdef VYRTUE_DEBUG
if (UNEXPECTED(NULL != getenv("PHP_VYRTUE_DEBUG_DUMP_AST"))) {
zend_string *str = zend_ast_export("<?php\n", ast, "");
Expand Down

0 comments on commit 0693fae

Please sign in to comment.