前言

本文通过分析 "$a=1" 这个 PHP 语句的编译和执行来窥探 php-cli 解释执行逻辑

准备

  • 参考之前的系列文章,在 ubuntu 环境下下载,编译 PHP 源代码

  • 将代码导入 idea clion IDE 中

  • 编辑运行选项,增加运行参数:-f test.php

  • 设置断点开始调试

test.php 是一个测试脚本,放在 sapi/cli/ 目录下,test.php 中只包含一条简单的赋值语句:

<?php
$a = 1
?>

调用堆栈

参考之前的系列文章来了解 php-cli 启动过程以及语法分析和字节码生成的基本概念,这里直接给出调用堆栈:

我们尝试从 zend_compile_expr 函数说起

zend_compile_expr

赋值语句 is-a 表达式,zend_compile_expr新视觉影院 函数根据 ast 类型选择调用 zend_compile_assign:

// zend_compile.c

void zend_compile_expr(znode *result, zend_ast *ast) {
...
switch (ast->kind) {
...
case ZEND_AST_ASSIGN:
zend_compile_assign(result, ast);
break;
}
}

zend_compile_assign

赋值语句的 ast 包含两个 child ast,即 left hand side var(ast->child[0]) 和 right hand side expr(ast->child[1]),var_node 和 expr_node 两个 znode 类型的变量是生成字节码过程使用的中间变量

// zend_compile.c

void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *var_ast = ast->child[0];
zend_ast *expr_ast = ast->child[1]; znode var_node, expr_node;
zend_op *opline;
uint32_t offset; if (is_this_fetch(var_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
} zend_ensure_writable_variable(var_ast);

然后我们来看看 switch case 语句

// zend_compile.c

switch (var_ast->kind) {
case ZEND_AST_VAR:
case ZEND_AST_STATIC_PROP:
offset = zend_delayed_compile_begin();
zend_delayed_compile_var(&var_node, var_ast, BP_VAR_W);
zend_compile_expr(&expr_node, expr_ast);
zend_delayed_compile_end(offset);
zend_emit_op(result, ZEND_ASSIGN, &var_node, &expr_node);
return;
}

刚看到这段代码可能会觉得挺绕的:zend_delayed_xxx 函数是干啥的?最终生成的字节码又保存在哪呢?

zend_emit_op

emit 有 "发射,散播"的意思,所以光棍影院 zend_emit_op 可能和字节码保存相关:

// zend_compile.c

static zend_op *zend_emit_op(znode *result, zend_uchar opcode,
znode *op1, znode *op2) /* {{{ */
{
zend_op *opline = get_next_op(CG(active_op_array));
opline->opcode = opcode; if (op1 == NULL) {
SET_UNUSED(opline->op1);
} else {
SET_NODE(opline->op1, op1);
} if (op2 == NULL) {
SET_UNUSED(opline->op2);
} else {
SET_NODE(opline->op2, op2);
} zend_check_live_ranges(opline);
if (result) {
zend_make_var_result(result, opline);
}
return opline;
}

这里我们又遇到了全局变量 CG(compile globals),zend_emit_op 先调用 get_next_op 获取可用的 zend_op(虚拟机指令),然后设置 op1, op2 为 opline 的两个操作数

现在我们知道生成的字节码保存在 CG 的 active_op_array 数组里

总结

PHP-7.1 源代码学习:字节码生成 之 "$a = 1"的更多相关文章

  1. Java代理全攻略【有瑕疵:字节码生成部分没看到,最后两节没仔细看,累了】

    Java代理 1.代理模式 定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象. 其实就是委托.聚合.中间人. 为了保持行为的 ...

  2. 曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎

    曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎 写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean De ...

  3. [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析

    [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...

  4. 谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署

    谁还没遇上过NoClassDefFoundError咋地--浅谈字节码生成与热部署 前言 在Java程序员的世界里,NoClassDefFoundError是一类相当令人厌恶的错误,因为这类错误通常非 ...

  5. 深入浅出Java探针技术2---java字节码生成框架ASM、Javassist和byte buddy的使用

    目前Java字节码生成框架大致有ASM.Javassist和byte buddy三种 ASM框架介绍及使用 1.ASM介绍 ASM是一种Java字节码操控框架,能够以二进制形式修改已有的类或是生成类, ...

  6. [WebKit内核] JavaScriptCore深度解析--基础篇(一)字节码生成及语法树的构建

    看到HorkeyChen写的文章<[WebKit] JavaScriptCore解析--基础篇(三)从脚本代码到JIT编译的代码实现>,写的很好,深受启发.想补充一些Horkey没有写到的 ...

  7. Kotlin字节码生成机制详尽分析

    通过注解修改Kotlin的class文件名: 对于Kotlin文件在编译之后生成的class文件名默认是有一定规则的,比如: 而其实这个生成字节码的文件名称是可以被改的,之前https://www.c ...

  8. 透过字节码生成审视Java动态代理运作机制

    对于动态代理我想应该大家都不陌生,就是可以动态去代理实现某个接口的类来干一些我们自己想要的功能,但是在字节码层面它的表现是如何的呢?既然目前刚好在研究字节码相关的东东,有必要对其从字节码角度来审视一下 ...

  9. JVM学习——字节码(学习过程)

    JVM--字节码 为什么要学字节码 字节码文件,有什么用? JVM虚拟机的特点:一处编译,多处运行. 多处运行,靠的是.class 字节码文件. JVM本身,并不是跨平台的.Java之所以跨平台,是因 ...

随机推荐

  1. (一)我的Javascript系列:Javascript的面向对象旅程(上)

    今宵酒醒何处,杨柳岸,晓风残月 导引 我的JavaScript系列文章是我自己对JavaScript语言的感悟所撰写的系列文章.现在还没有写完.目前一共出了下面的系列: (三)我的JavaScript ...

  2. GoAccess安装和使用介绍

    使用文档参考地址:https://my.oschina.net/mrco/blog/181737https://www.fanhaobai.com/2017/06/go-access.html goa ...

  3. 家校通Code

    9 http://dlwt.csdn.net/fd.php?i=621573845033702&s=44d46a459acce7fef39aa4dcff51bfba

  4. JavaSe-算数运算符

    算数运算符包括:+.-.*./.%.++.-- 代码: package com.java.chap02; public class Demo07 { public static void main(S ...

  5. BZOJ 4175: 小G的电话本 SAM+FFT

    4175: 小G的电话本 Time Limit: 45 Sec  Memory Limit: 256 MBSubmit: 195  Solved: 48[Submit][Status][Discuss ...

  6. ZOJ 1729 Hidden Password (字符串最小表示)

    以前听过,不知道是什么,其实就是字符串首尾相连成一个环,n种切法求一个字典序最小的表示. 朴素算法大家都懂.O(n)的算法代码非常简单,最主要的思想是失配的时候尽可能大的移动指针. 另外附上一个不错的 ...

  7. Spring归纳

    Spring总结 bean标签的scope属性 scope="singleton",单例模式,默认值 scope="prototype",多例模式 注解元素 @ ...

  8. Android layout的XML

    [注]此文是在学习andriod中的一些理解和总结,若有错望留言指教,谢谢 1 <RelativeLayout xmlns:android="http://schemas.androi ...

  9. C Library - <limits.h>

    Introduction The limits.h header determines various properties of the various variable types. The ma ...

  10. SpringMVC的controller层的方法返回值

    1.ModelAndView  既带着数据,又返回视图路劲 2.String 返回试图路径  model带数据  (官方或企业推荐使用此种方式 ,此方法符合解耦思想,即数据,视图,分离 MVC) 3. ...