1. 问题
调试QuickJS碰到一行语句:
if (vd->scope_level == 0 && vd->func_pool_idx >= 0)
{
LOG_OUT("[Info] vd->scope_level %d, vd->func_pool_idx = %d, (vd->func_pool_idx>=0)? %d", vd->scope_level, vd->func_pool_idx, vd->func_pool_idx >= 0);
.....
}
输出的结果:
vd->scope_level 0, vd->func_pool_idx = -1, (vd->func_pool_idx>=0)? 1
明明是 -1 为什么会和0比较会大于0?
2. 分析
经过分析才知道,该成员变量是一个位域变量,占用24bit, 但是是整数有符号定义;
typedef struct JSVarDef {
JSAtom var_name;
/* index into fd->scopes of this variable lexical scope */
int scope_level;
/* during compilation:
- if scope_level = 0: scope in which the variable is defined
- if scope_level != 0: index into fd->vars of the next
variable in the same or enclosing lexical scope
in a bytecode function:
index into fd->vars of the next
variable in the same or enclosing lexical scope
*/
int scope_next;
uint8_t is_const : 1;
uint8_t is_lexical : 1;
uint8_t is_captured : 1;
uint8_t var_kind : 4; /* see JSVarKindEnum */
int func_pool_idx : 24; /* only used during compilation : index in
the constant pool for hoisted function
definition */
} JSVarDef;
经过查汇编知道该位域变量的读取时按照无符号数读取的,其中指令UBFX就是读取的无符号位域指令。
if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
0x020cb472: 687b {h LDR r3,[r7,#4]
0x020cb474: b9eb .. CBNZ r3,0x20cb4b2 ;
0x020cb476: 68f8 .h LDR r0,[r7,#0xc]
0x020cb478: 2101 .! MOVS r1,#1
0x020cb47a: f3c010d7 .... UBFX r0,r0,#7,#24
0x020cb47e: e9cd0100 .... STRD r0,r1,[sp,#0]
0x020cb482: 493f ?I LDR r1,[pc,#252] ; [0x20cb580] = 0x8809748
0x020cb484: 2203 ." MOVS r2,#3
0x020cb486: 3128 (1 ADDS r1,r1,#0x28
0x020cb488: 483c <H LDR r0,[pc,#240] ; [0x20cb57c] = 0x6f103002
}
这就导致数据处理流程出现问题!
3. 解决方法
这里的编译环境使用给的arm keil + compiler version5, 经查编译选项 keil中有一个指定位域是否为符号类型的选项;
为了不影响整个工程的配置,针对QuickJS所在的组单独配置 --signed_bitfields, 如下:
配置完成之后再次运行程序运行正常,汇编如下:
if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
0x020cb47c: 687b {h LDR r3,[r7,#4]
0x020cb47e: bb03 .. CBNZ r3,0x20cb4c2 ;
0x020cb480: 68f8 .h LDR r0,[r7,#0xc]
0x020cb482: f34010d7 @... SBFX r0,r0,#7,#24
0x020cb486: 2800 .( CMP r0,#0
0x020cb488: db1b .. BLT 0x20cb4c2 ;