资讯专栏INFORMATION COLUMN

PHP-7.1 源代码学习:字节码生成 之 概述

1fe1se / 1635人阅读

摘要:前言字节码生成编译的代码主要集中在,文件中包含大量的函数,基本上一个函数对应语法规则文件一个非终结符,函数是所有函数的入口数据结构结构体是字节码抽象结构体并没有像名字那样简单,它包含了大量的字段供虚拟机在运行时使用一如既往的简单,直观,相比

前言

字节码生成(编译)的代码主要集中在 zend_compile.c ,文件中包含大量的 zend_compile_xxx 函数,基本上一个函数对应 语法规则文件 zend_language_parser.y 一个非终结符,zend_compile_top_stmt 函数是所有 zend_compile_xxx 函数的入口

数据结构 zend_op

zend_op 结构体是 PHP 字节码抽象

// zend_compile.h

struct _zend_op {
    const void *handler;
    znode_op op1;
    znode_op op2;
    znode_op result;
    uint32_t extended_value;
    uint32_t lineno;
    zend_uchar opcode;
    zend_uchar op1_type;
    zend_uchar op2_type;
    zend_uchar result_type;
}
zend_op_array

zend_op_array 结构体并没有像名字那样简单 zend op array,它包含了大量的字段供虚拟机在运行时使用

// zend_compile.h

struct _zend_op_array {
}
zend_compile_top_stmt

zend_compile_top_stmt 一如既往的简单,直观,相比之前看 ruby 源代码而言,感觉 欧美工程师 可能真的比 岛国工程师 牛叉一些

// zend_compile.c

void zend_compile_top_stmt(zend_ast *ast) {
    if (!ast) {
        return;
    }

    if (ast->kind == ZEND_AST_STMT_LIST) {
        zend_ast_list *list = zend_ast_get_list(ast);
        uint32_t i;
        for (i = 0; i < list->children; ++i) {
            zend_compile_top_stmt(list->child[i]);
        }
        return;
    }

    zend_compile_stmt(ast);

    if (ast->kind != ZEND_AST_NAMESPACE && ast->kind != ZEND_AST_HALT_COMPILER) {
        zend_verify_namespace();
    }
    if (ast->kind == ZEND_AST_FUNC_DECL || ast->kind == ZEND_AST_CLASS) {
        CG(zend_lineno) = ((zend_ast_decl *) ast)->end_lineno;
        zend_do_early_binding();
    }
}

ast 是抽象语法树(AST)的根节点(参考 PHP-7.1 源代码学习:语法分析 之 概述),函数首先对 ast 进行参数验证,针对 ZEND_AST_STMT_LIST 节点类型进行递归调用,然后调用 zend_compile_stmt 编译 各个 stmt,这个流程和语法规则也是精确对应的:

start: top_statement_list { CG(ast) = $1 }
top_statement_list:
        top_statement_list top_statement { $$ = zend_ast_list_add($1, $2) }
    |    /* empty */ { $$ = zend_ast_create_list(0, ZEND_AST_STMT_LIST); }
top_statement:
    statement
    ...
zend_compile_stmt

zend_compile_stmt 函数基本上就是根据 zend_ast 类型(kind)进行 switch case

void zend_compile_stmt(zend_ast *ast) {
    if (!ast) {
        return;
    }

    CG(zend_lineno) = ast->lineno;
    ...
    switch (ast->kind) {
        case ZEND_AST_STMT_LIST:
            zend_compile_stmt_list(ast);
            break;
        case ZEND_AST_GLOBAL:
            zend_compile_global_var(ast);
            break;
        ...
        default:
        {
            znode result;
            zend_compile_expr(&result, ast);
            zend_do_free(&result);
        }
    }
    ...
}
总结

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/22323.html

相关文章

  • PHP-7.1 源代学习字节在 Zend 虚拟机中的解释执行 概述

    摘要:前言本文简要介绍虚拟机解释执行字节码的基本逻辑以及相关的数据结构,关于源代码的下载,编译,调试可以参考之前的系列文章我们来看看执行一个简单的脚本的调用栈由于是执行脚本文件,所以调用了函数,最终调用函数和其它语言编写的系统软件类似,函数中 前言 本文简要介绍 zend 虚拟机解释执行字节码的基本逻辑以及相关的数据结构,关于 PHP 源代码的下载,编译,调试可以参考之前的系列文章 exec...

    Tamic 评论0 收藏0
  • PHP-7.1 源代学习字节生成 "$a = 1"

    摘要:前言本文通过分析这个语句的编译和执行来窥探解释执行逻辑准备参考之前的系列文章,在环境下下载,编译源代码将代码导入中编辑运行选项,增加运行参数设置断点开始调试是一个测试脚本,放在目录下,中只包含一条简单的赋值语句调用堆栈参考之前的系列文章 前言 本文通过分析 $a=1 这个 PHP 语句的编译和执行来窥探 php-cli 解释执行逻辑 准备 参考之前的系列文章,在 ubuntu 环境下...

    ConardLi 评论0 收藏0
  • PHP-7.1 源代学习:代生成 函数定义

    摘要:前言本文从函数定义的语法规则开始,简要介绍解释器如何编译函数定义函数对应的节点为了看起来清楚一些,我们将语法规则定义与语法动作分开根据语法动作,这条函数定义规则会创建一个类型的结点,我们来看看方法是一个通用的方法,通 前言 本文从函数定义的语法规则开始,简要介绍 PHP 解释器如何 编译 函数定义 函数对应的 AST 节点 为了看起来清楚一些,我们将 语法规则定义 与 语法动作分开: ...

    aisuhua 评论0 收藏0
  • PHP-7.1 源代学习:虚拟机字节

    前言 to be done 总结

    李增田 评论0 收藏0
  • PHP-7.1 源代学习php-cli 启动流程

    摘要:前言函数默认构建目标为,相关代码在目录下,文件中能够找到入口函数,大概流程如下命令行参数处理初始化清理工作语言系统编程常用手法,通过中声明函数指针类型的字段来实现类似面向对象中抽象类的概念,在文件中可以找到该结构体的定义,这里只列出部分 前言 php cli main 函数 configure & make 默认构建目标为 php-cli,相关代码在 sapi/cli 目录下,php_...

    VishKozus 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<