本文基于 Python 3.6.4 编译器生成字节码,你可通过如下代码片段得到
python 源码对应的字节码
#!/usr/bin/env python
# encoding: utf-8
import sys
import dis
filename=sys.argv[1]
f = open(filename, 'rb')
content = f.read()
c = compile(content, filename, "exec")
dis.dis(c)
所有的字节码都位于 Python/ceval.c 文件
//元祖的第 i 个元素
#define GETITEM(v, i) PyTuple_GetItem((v), (i))
//调整栈顶指针
#define BASIC_STACKADJ(n) (stack_pointer += n)
#define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \
lltrace && prtrace(TOP(), "stackadj")); \
assert(STACK_LEVEL() <= co->co_stacksize); }
//入栈
#define BASIC_PUSH(v) (*stack_pointer++ = (v))
#define PUSH(v) { (void)(BASIC_PUSH(v), \
lltrace && prtrace(TOP(), "push")); \
assert(STACK_LEVEL() <= co->co_stacksize); }
//出栈
#define BASIC_POP() (*--stack_pointer)
#define POP() ((void)(lltrace && prtrace(TOP(), "pop")), \
BASIC_POP())
//指向下一条指令
#define DISPATCH() \
{ \
if (!_Py_atomic_load_relaxed(&eval_breaker)) { \
FAST_DISPATCH(); \
} \
continue; \
}
#ifdef LLTRACE
#define FAST_DISPATCH() \
{ \
if (!lltrace && !_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
} \
goto fast_next_opcode; \
}
#else
#define FAST_DISPATCH() \
{ \
if (!_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
} \
goto fast_next_opcode; \
}
#endif
#define JUMPBY(x) (next_instr += (x) / sizeof(_Py_CODEUNIT))
#define JUMPTO(x) (next_instr = first_instr + (x) / sizeof(_Py_CODEUNIT))
typedef uint16_t _Py_CODEUNIT
#!/usr/bin/env python
# encoding: utf-8
i = 1
s = "Python"
d = {}
l = {}
对应的字节码为
4 0 LOAD_CONST 0 (1)
2 STORE_NAME 0 (i)
5 4 LOAD_CONST 1 ('Python')
6 STORE_NAME 1 (s)
6 8 BUILD_MAP 0
10 STORE_NAME 2 (d)
12 LOAD_CONST 2 (None)
14 RETURN_VALUE
注:第一列为源代码行号,第二列为指令索引, 第三列为指令,第四列为指令的参数,第五列为指令参数对应的值(提示)。
TARGET(LOAD_CONST) {
# 从常量表中获取索引为 oparg 的元素,其值为 value
PyObject *value = GETITEM(consts, oparg);
Py_INCREF(value);
PUSH(value);
FAST_DISPATCH();
}
TARGET(STORE_NAME) {
//从符号表获取第 oparg 个元素作为变量名 name
PyObject *name = GETITEM(names, oparg);
//将栈顶元素赋值给 v,并将栈指针减 1
PyObject *v = POP();
PyObject *ns = f->f_locals;
int err;
if (ns == NULL) {
PyErr_Format(PyExc_SystemError,
"no locals found when storing %R", name);
Py_DECREF(v);
goto error;
}
if (PyDict_CheckExact(ns))
//f->f_locals 中设置 name = v
err = PyDict_SetItem(ns, name, v);
else
//ns.name = v
err = PyObject_SetItem(ns, name, v);
//引用减一
Py_DECREF(v);
if (err != 0)
goto error;
DISPATCH();
}
#define PEEK(n) (stack_pointer[-(n)])
TARGET(BUILD_MAP) {
Py_ssize_t i;
//创建一个字典,初始元素个数为 oparg
PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
if (map == NULL)
goto error;
for (i = oparg; i > 0; i--) {
int err;
//找到 key
PyObject *key = PEEK(2*i);
//找到 value
PyObject *value = PEEK(2*i - 1);
//设置 map[key] = value
err = PyDict_SetItem(map, key, value);
if (err != 0) {
Py_DECREF(map);
goto error;
}
}
while (oparg--) {
Py_DECREF(POP());
Py_DECREF(POP());
}
PUSH(map);
DISPATCH();
}
TARGET(BUILD_LIST) {
//创建一个列表,初始元素个数为 oparg
PyObject *list = PyList_New(oparg);
if (list == NULL)
goto error;
//从后往前
while (--oparg >= 0) {
//从栈中弹出一个元素
PyObject *item = POP();
//设置 list[oparg] = item
PyList_SET_ITEM(list, oparg, item);
}
//list 压栈
PUSH(list);
DISPATCH();
}
TARGET(RETURN_VALUE) {
retval = POP();
why = WHY_RETURN;
goto fast_block_end;
}
例 2
#!/usr/bin/env python
# encoding: utf-8
a = 1
b = "Python"
c = a + b
4 0 LOAD_CONST 0 (1)
3 STORE_NAME 0 (a)
5 6 LOAD_CONST 1 ('Python')
9 STORE_NAME 1 (b)
6 12 LOAD_NAME 0 (a)
15 LOAD_NAME 1 (b)
18 BINARY_ADD
19 STORE_NAME 2 (c)
22 LOAD_CONST 2 (None)
25 RETURN_VALUE
TARGET(LOAD_NAME) {
//从符号表加载中第 oparg 个元素 name,依次从局部变量表,全局变量表,
//内置变量表中查找 name 对应找到值,如果找到将该值压栈,如果没有找到抛异常。
PyObject *name = GETITEM(names, oparg);
PyObject *locals = f->f_locals;
PyObject *v;
//确保局部变量表存在 name
if (locals == NULL) {
PyErr_Format(PyExc_SystemError,
"no locals when loading %R", name);
goto error;
}
//如果是字典对象,从局部变量表中获取 name 对应的值
if (PyDict_CheckExact(locals)) {
v = PyDict_GetItem(locals, name);
Py_XINCREF(v);
}
else {
v = PyObject_GetItem(locals, name);
if (v == NULL) {
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
PyErr_Clear();
}
}
//如果局部变量表不存在该变量,从全局变量中查找
if (v == NULL) {
v = PyDict_GetItem(f->f_globals, name);
Py_XINCREF(v);
if (v == NULL) {
# 如果全局变量表中也不存在,从内置变量表中查找
if (PyDict_CheckExact(f->f_builtins)) {
v = PyDict_GetItem(f->f_builtins, name);
if (v == NULL) {
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, name);
goto error;
}
Py_INCREF(v);
}
else {
v = PyObject_GetItem(f->f_builtins, name);
if (v == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError))
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, name);
goto error;
}
}
}
}
PUSH(v);
DISPATCH();
}
TARGET(BINARY_ADD) {
//从栈中弹出右边的变量
PyObject *right = POP();
//获取栈顶元素,可见入栈从左往右
PyObject *left = TOP();
PyObject *sum;
if (PyUnicode_CheckExact(left) &&
PyUnicode_CheckExact(right)) {
//字符串连接
sum = unicode_concatenate(left, right, f, next_instr);
/* unicode_concatenate consumed the ref to left */
}
else {
//数字相加
sum = PyNumber_Add(left, right);
Py_DECREF(left);
}
Py_DECREF(right);
//直接将栈顶元素设置为叠加之后的值,避免了两次栈操作
SET_TOP(sum);
if (sum == NULL)
goto error;
DISPATCH();
}
#!/usr/bin/env python
# encoding: utf-8
c = { "1" : "a", "2": "b" }
c = [1, 2, 3]
4 0 BUILD_MAP 2
3 LOAD_CONST 0 ('a')
6 LOAD_CONST 1 ('1')
9 STORE_MAP
10 LOAD_CONST 2 ('b')
13 LOAD_CONST 3 ('2')
16 STORE_MAP
17 STORE_NAME 0 (c)
5 20 LOAD_CONST 4 (1)
23 LOAD_CONST 5 (2)
26 LOAD_CONST 6 (3)
29 BUILD_LIST 3
32 STORE_NAME 0 (c)
35 LOAD_CONST 7 (None)
38 RETURN_VALUE
可见 map 是加载一个元素,写入 map,再加载一个元素,再写入,依次类推
而 list 一次将所有元素写入栈,然后写入 list
哈哈,这里 list 会不会有栈溢出攻击呢? 我试了下 500 元素构造 list
也是压栈 500 次,之后再加入 list
#!/usr/bin/env python
# encoding: utf-8
a = 2
print(a)
4 0 LOAD_CONST 0 (2)
2 STORE_NAME 0 (a)
5 4 LOAD_NAME 1 (print)
6 LOAD_NAME 0 (a)
8 CALL_FUNCTION 1
10 POP_TOP
12 LOAD_CONST 1 (None)
14 RETURN_VALUE
PREDICTED(CALL_FUNCTION);
TARGET(CALL_FUNCTION) {
PyObject **sp, *res;
PCALL(PCALL_ALL);
sp = stack_pointer;
res = call_function(&sp, oparg, NULL);
stack_pointer = sp;
PUSH(res);
if (res == NULL) {
goto error;
}
DISPATCH();
}
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
static PyObject *
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
{
PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
PyObject *x, *w;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nargs = oparg - nkwargs;
PyObject **stack;
/* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object.
*/
if (PyCFunction_Check(func)) {
PyThreadState *tstate = PyThreadState_GET();
PCALL(PCALL_CFUNCTION);
stack = (*pp_stack) - nargs - nkwargs;
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
}
else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
/* optimize access to bound methods */
PyObject *self = PyMethod_GET_SELF(func);
PCALL(PCALL_METHOD);
PCALL(PCALL_BOUND_METHOD);
Py_INCREF(self);
func = PyMethod_GET_FUNCTION(func);
Py_INCREF(func);
Py_SETREF(*pfunc, self);
nargs++;
}
else {
Py_INCREF(func);
}
stack = (*pp_stack) - nargs - nkwargs;
if (PyFunction_Check(func)) {
x = fast_function(func, stack, nargs, kwnames);
}
else {
x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
}
Py_DECREF(func);
}
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
/* Clear the stack of the function object. Also removes
the arguments in case they weren't consumed already
(fast_function() and err_args() leave them on the stack).
*/
while ((*pp_stack) > pfunc) {
w = EXT_POP(*pp_stack);
Py_DECREF(w);
PCALL(PCALL_POP);
}
return x;
}
#!/usr/bin/env python
# encoding: utf-8
a = 2
if a > 1:
a = 0
编译之后
4 0 LOAD_CONST 0 (2)
2 STORE_NAME 0 (a)
5 4 LOAD_NAME 0 (a)
6 LOAD_CONST 1 (1)
8 COMPARE_OP 4 (>)
10 POP_JUMP_IF_FALSE 16
6 12 LOAD_CONST 2 (0)
14 STORE_NAME 0 (a)
>> 16 LOAD_CONST 3 (None)
18 RETURN_VALUE
static PyObject * cmp_outcome(int op, PyObject *v, PyObject *w)
{
int res = 0;
switch (op) {
//...
default:
return PyObject_RichCompare(v, w, op);
}
v = res ? Py_True : Py_False;
Py_INCREF(v);
return v;
}
PyObject *
PyObject_RichCompare(PyObject *v, PyObject *w, int op)
{
PyObject *res;
assert(Py_LT <= op && op <= Py_GE);
if (v == NULL || w == NULL) {
if (!PyErr_Occurred())
PyErr_BadInternalCall();
return NULL;
}
if (Py_EnterRecursiveCall(" in comparison"))
return NULL;
res = do_richcompare(v, w, op);
Py_LeaveRecursiveCall();
return res;
}
//由下可知实际调用的是对象类型的 ob_type->tp_richcompare
static PyObject *
do_richcompare(PyObject *v, PyObject *w, int op)
{
richcmpfunc f;
PyObject *res;
int checked_reverse_op = 0;
if (v->ob_type != w->ob_type &&
PyType_IsSubtype(w->ob_type, v->ob_type) &&
(f = w->ob_type->tp_richcompare) != NULL) {
checked_reverse_op = 1;
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if ((f = v->ob_type->tp_richcompare) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if (!checked_reverse_op && (f = w->ob_type->tp_richcompare) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
/* If neither object implements it, provide a sensible default
for == and !=, but raise an exception for ordering. */
switch (op) {
case Py_EQ:
res = (v == w) ? Py_True : Py_False;
break;
case Py_NE:
res = (v != w) ? Py_True : Py_False;
break;
default:
PyErr_Format(PyExc_TypeError,
"'%s' not supported between instances of '%.100s' and '%.100s'",
opstrings[op],
v->ob_type->tp_name,
w->ob_type->tp_name);
return NULL;
}
Py_INCREF(res);
return res;
}
TARGET(COMPARE_OP) {
//弹出右值
PyObject *right = POP();
//取左值
PyObject *left = TOP();
//
PyObject *res = cmp_outcome(oparg, left, right);
Py_DECREF(left);
Py_DECREF(right);
//结果写入栈顶
SET_TOP(res);
if (res == NULL)
goto error;
//没有找到 PRED_XXXX 相关代码,但从 C 语言的经验来看应该是分支预测相关,
//当然这与我们掌握字节码本身关系也不是特别大,暂且跳过。
PREDICT(POP_JUMP_IF_FALSE);
PREDICT(POP_JUMP_IF_TRUE);
DISPATCH();
}
#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS
#define PREDICT(op) if (0) goto PRED_##op
#else
#define PREDICT(op) \
do{ \
_Py_CODEUNIT word = *next_instr; \
opcode = _Py_OPCODE(word); \
if (opcode == op){ \
oparg = _Py_OPARG(word); \
next_instr++; \
goto PRED_##op; \
} \
} while(0)
#endif
#define PREDICTED(op) PRED_##op:
PREDICTED(POP_JUMP_IF_FALSE);
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
//如果为 True,继续执行
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
}
//如果为 False,跳转到参数 oparg 的位置
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
//如果不是 bool 类型,大于 0,设置 err = 0
//等于 0,跳转到参数 oparg 位置,小于 0,报错
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0)
err = 0;
else if (err == 0)
JUMPTO(oparg);
else
goto error;
DISPATCH();
}
PREDICTED(POP_JUMP_IF_TRUE);
TARGET(POP_JUMP_IF_TRUE) {
PyObject *cond = POP();
int err;
if (cond == Py_False) {
Py_DECREF(cond);
FAST_DISPATCH();
}
if (cond == Py_True) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0) {
err = 0;
JUMPTO(oparg);
}
else if (err == 0)
;
else
goto error;
DISPATCH();
}
#!/usr/bin/env python
# encoding: utf-8
a = [1, 2, 3]
for e in a:
b = e
9 0 LOAD_CONST 0 (1)
2 LOAD_CONST 1 (2)
4 LOAD_CONST 2 (3)
6 BUILD_LIST 3
8 STORE_NAME 0 (a)
10 10 SETUP_LOOP 16 (to 28)
12 LOAD_NAME 0 (a)
14 GET_ITER
# 8/2 = 4,向前跳 4 条指令,本例到了 POP_BLOCK
>> 16 FOR_ITER 8 (to 26)
18 STORE_NAME 1 (e)
11 20 LOAD_NAME 1 (e)
22 STORE_NAME 2 (b)
24 JUMP_ABSOLUTE 16 //调到 FOR_ITER
>> 26 POP_BLOCK
>> 28 LOAD_CONST 3 (None)
30 RETURN_VALUE
const _Py_CODEUNIT *first_instr;
const _Py_CODEUNIT *next_instr;
first_instr = (_Py_CODEUNIT *) PyBytes_AS_STRING(co->co_code);
#define INSTR_OFFSET() (sizeof(_Py_CODEUNIT) * (int)(next_instr - first_instr))
TARGET(SETUP_LOOP) {
PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,
STACK_LEVEL());
DISPATCH();
}
//Objects/frameobject.c
void
PyFrame_BlockSetup(PyFrameObject *f, int type, int handler, int level)
{
PyTryBlock *b;
//哈哈,还有代码块溢出 #define CO_MAXBLOCKS 20
if (f->f_iblock >= CO_MAXBLOCKS)
Py_FatalError("XXX block stack overflow");
//将代码块深度加一
b = &f->f_blockstack[f->f_iblock++];
b->b_type = type;
b->b_level = level;
b->b_handler = handler;
}
//Include/frameobject.h
typedef struct {
int b_type; /* what kind of block this is */
int b_handler; /* where to jump to find handler */
int b_level; /* value stack level to pop to */
} PyTryBlock;
typedef struct _frame {
//....
int f_lineno; /* Current line number */
int f_iblock; /* index in f_blockstack */
char f_executing; /* whether the frame is still executing */
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
} PyFrameObject;
TARGET(GET_ITER) {
/* before: [obj]; after [getiter(obj)] */
//获取栈顶元素
PyObject *iterable = TOP();
//获取栈顶元素的迭代器,对于 Python 来说,每个对象的类似都是
//PyTypeObject,而 PyTypeObject 都有一个成员 tp_iter 表示其迭代器。
//此处不再详述,参考 Objects/abstract.c
PyObject *iter = PyObject_GetIter(iterable);
Py_DECREF(iterable);
//用迭代器替代原有栈顶元素
SET_TOP(iter);
if (iter == NULL)
goto error;
PREDICT(FOR_ITER);
PREDICT(CALL_FUNCTION);
DISPATCH();
}
PREDICTED(FOR_ITER);
TARGET(FOR_ITER) {
/* before: [iter]; after: [iter, iter()] *or* [] */
//由 GET_ITER 得知,当前栈顶为 iter
PyObject *iter = TOP();
//获取下一个元素
PyObject *next = (*iter->ob_type->tp_iternext)(iter);
if (next != NULL) {
//压栈
PUSH(next);
PREDICT(STORE_FAST);
PREDICT(UNPACK_SEQUENCE);
//continue 的作用是继续执行下一条指令
DISPATCH();
}
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_StopIteration))
goto error;
else if (tstate->c_tracefunc != NULL)
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f);
PyErr_Clear();
}
/* iterator ended normally */
STACKADJ(-1);
Py_DECREF(iter);
JUMPBY(oparg);
PREDICT(POP_BLOCK);
DISPATCH();
}
PREDICTED(JUMP_ABSOLUTE);
TARGET(JUMP_ABSOLUTE) {
JUMPTO(oparg);
#if FAST_LOOPS
/* Enabling this path speeds-up all while and for-loops by bypassing
the per-loop checks for signals. By default, this should be turned-off
because it prevents detection of a control-break in tight loops like
"while 1: pass". Compile with this option turned-on when you need
the speed-up and do not need break checking inside tight loops (ones
that contain only instructions ending with FAST_DISPATCH).
*/
FAST_DISPATCH();
#else
DISPATCH();
#endif
}
PREDICTED(POP_BLOCK);
TARGET(POP_BLOCK) {
PyTryBlock *b = PyFrame_BlockPop(f);
UNWIND_BLOCK(b);
DISPATCH();
}
PyTryBlock *
PyFrame_BlockPop(PyFrameObject *f)
{
PyTryBlock *b;
if (f->f_iblock <= 0)
Py_FatalError("XXX block stack underflow");
//将代码块深度减一
b = &f->f_blockstack[--f->f_iblock];
return b;
}
因此,整个 for 循环的结构如下
SETUP_LOOP
...
GET_ITER
FOR_ITER
...
JUMP_ABSOLUTE
POP_BLOCK
在创建 for 循环的时候 b = &f->f_blockstack[f->f_iblock++];
for 循环执行完的时候 b = &f->f_blockstack[–f->f_iblock];
最后,
#!/usr/bin/env python
# encoding: utf-8
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
for i in range(10):
a = 1
这估计是一道非常难的 python 面试题了, 猜猜结果是什么,哈哈,如果换成 21 层 for
循环呢?
#!/usr/bin/env python
# encoding: utf-8
i = 0
while i > 10:
i += 1
if i > 5:
continue
if i == 9:
break
b = 1
字节码
9 0 LOAD_CONST 0 (0)
2 STORE_NAME 0 (i)
10 4 SETUP_LOOP 44 (to 50)
>> 6 LOAD_NAME 0 (i)
8 LOAD_CONST 1 (10)
10 COMPARE_OP 0 (<)
12 POP_JUMP_IF_FALSE 48
11 14 LOAD_NAME 0 (i)
16 LOAD_CONST 2 (1)
18 INPLACE_ADD
20 STORE_NAME 0 (i)
12 22 LOAD_NAME 0 (i)
24 LOAD_CONST 3 (5)
26 COMPARE_OP 4 (>)
28 POP_JUMP_IF_FALSE 32
13 30 JUMP_ABSOLUTE 6 //continue
14 >> 32 LOAD_NAME 0 (i)
34 LOAD_CONST 4 (9)
36 COMPARE_OP 2 (==)
38 POP_JUMP_IF_FALSE 42
15 40 BREAK_LOOP
16 >> 42 LOAD_CONST 2 (1)
44 STORE_NAME 1 (b)
46 JUMP_ABSOLUTE 6
>> 48 POP_BLOCK
>> 50 LOAD_CONST 5 (None)
52 RETURN_VALUE
TARGET(BREAK_LOOP) {
why = WHY_BREAK;
goto fast_block_end;
}
fast_block_end:
/* Unwind stacks if a (pseudo) exception occurred */
while (why != WHY_NOT && f->f_iblock > 0) {
/* Peek at the current block. */
PyTryBlock *b = &f->f_blockstack[f->f_iblock - 1];
/* Now we have to pop the block. */
f->f_iblock--;
if (b->b_type == EXCEPT_HANDLER) {
UNWIND_EXCEPT_HANDLER(b);
continue;
}
UNWIND_BLOCK(b);
//执行这里
if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {
//设置 why
why = WHY_NOT;
//调整到 b->b_handler,b->b_handler 实际上就是 SETUP_LOOP 的参数
JUMPTO(b->b_handler);
break;
}
剩下的都是熟悉的指令,熟悉的面孔。
因此,整个 for 循环的结构如下
SETUP_LOOP
...
COMPARE_OP
POP_JUMP_IF_FALSE
...
JUMP_ABSOLUTE
POP_BLOCK
在创建 for 循环的时候 b = &f->f_blockstack[f->f_iblock++];
for 循环执行完的时候 b = &f->f_blockstack[–f->f_iblock];