欢迎光临
我们一直在努力

《Chrome V8源码》26.Bytecode Handler,字节码的核心

 

1 摘要

本篇文章是Builtin专题的第二篇,讲解Bytecode Handler的初始化过程以及相关数据结构。Bytecode handler是采用CAS方式编写的Builtin,它实现了Bytecode的功能,每一条Bytecode对应一条Bytecode handler。本文内容组织方法:Bytecode handler介绍(章节2);Bytecode Handler初始化(章节3)。

 

2 Bytecode Handler介绍

Bytecode handler的地址保存在Dispatch_table数组中,Dispatch_table保存在Isolate中。每一条Bytecode执行完毕后通过Dispatch_table找到下一条Bytecode并完成跳转。Bytecode handler的源码在interpreter-generator.cc文件中,其中Star和Mov的源码如下:

1.  // Store accumulator to register <dst>.
2. IGNITION_HANDLER(Star, InterpreterAssembler) {
3. TNode<Object> accumulator = GetAccumulator();
4. StoreRegisterAtOperandIndex(accumulator, 0);
5. Dispatch();
6. }
7. // Mov <src> <dst>
8. //
9. // Stores the value of register <src> to register <dst>.
10. IGNITION_HANDLER(Mov, InterpreterAssembler) {
11. TNode<Object> src_value = LoadRegisterAtOperandIndex(0);
12. StoreRegisterAtOperandIndex(src_value, 1);
13. Dispatch();
14. }

上述代码中,Dispatch()利用Isolate读取Dispatch_table并跳转到下一条指令。

 

3 Bytecode Handler初始化

Bytecode handler是用CodeStubAssembler编写的Builtin。第一个Isolate创建时,Bytecode handler完成初始化并存储在dispatch_table中,后续创建新的Isoalte时无需再做初始化,只需要拷贝即可。
Bytecode Handler初始化的入口源码如下:

1.  void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
2. Builtins* builtins = isolate->builtins();
3. int index = 0;
4. Code code;
5. //...........省略............................
6. #define BUILD_BCH(Name, OperandScale, Bytecode) \\
7. code = GenerateBytecodeHandler(isolate, index, OperandScale, Bytecode); \\
8. AddBuiltin(builtins, index++, code);
9. BUILTIN_LIST(BUILD_CPP, BUILD_TFJ, BUILD_TFC, BUILD_TFS, BUILD_TFH, BUILD_BCH,
10. BUILD_ASM);
11. //.........省略............................
12. }

BUILD_BCH、BUILTIN_LIST和GenerateBytecodeHandler()共同完成所有Bytecode handler的创建,GenerateBytecodeHandler()源码如下:

Code GenerateBytecodeHandler(Isolate* isolate, int builtin_index,
interpreter::OperandScale operand_scale,
interpreter::Bytecode bytecode) {
DCHECK(interpreter::Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
Handle<Code> code = interpreter::GenerateBytecodeHandler(
isolate, Builtins::name(builtin_index), bytecode, operand_scale,
builtin_index, BuiltinAssemblerOptions(isolate, builtin_index));
return *code;
}

上述代码中Builtins::name(builtin_index)获取Bytecode的名字,源码如下:

const char* Builtins::name(int index) {
DCHECK(IsBuiltinId(index));
return builtin_metadata[index].name;
}
//................分隔线.......................
#define DECL_CPP(Name, ...) \\
{#Name, Builtins::CPP, {FUNCTION_ADDR(Builtin_##Name)}},
#define DECL_TFJ(Name, Count, ...) {#Name, Builtins::TFJ, {Count, 0}},
#define DECL_TFC(Name, ...) {#Name, Builtins::TFC, {}},
#define DECL_TFS(Name, ...) {#Name, Builtins::TFS, {}},
#define DECL_TFH(Name, ...) {#Name, Builtins::TFH, {}},
#define DECL_BCH(Name, OperandScale, Bytecode) \\
{#Name, Builtins::BCH, {Bytecode, OperandScale}},
#define DECL_ASM(Name, ...) {#Name, Builtins::ASM, {}},
const BuiltinMetadata builtin_metadata[] = {BUILTIN_LIST(
DECL_CPP, DECL_TFJ, DECL_TFC, DECL_TFS, DECL_TFH, DECL_BCH, DECL_ASM)};

上述代码中builtin_metadata数组保存每一条Bytecode的名字、类型和地址指针。如图1中所示,1075号Builtin的名字是DebugBreak0Handler,类型是BCH(Bytecode handler),函数地址是data。

在Code GenerateBytecodeHandler()中调用interpreter::GenerateBytecodeHandler(),源码如下:

1.  Handle<Code> GenerateBytecodeHandler(Isolate* isolate, const char* debug_name,
2. Bytecode bytecode,
3. OperandScale operand_scale,
4. int builtin_index,
5. const AssemblerOptions& options) {
6. Zone zone(isolate->allocator(), ZONE_NAME);
7. compiler::CodeAssemblerState state(
8. isolate, &zone, InterpreterDispatchDescriptor{}, Code::BYTECODE_HANDLER,
9. debug_name,
10. FLAG_untrusted_code_mitigations
11. ? PoisoningMitigationLevel::kPoisonCriticalOnly
12. : PoisoningMitigationLevel::kDontPoison,
13. builtin_index);
14. switch (bytecode) {
15. #define CALL_GENERATOR(Name, ...) \\
16. case Bytecode::k##Name: \\
17. Name##Assembler::Generate(&state, operand_scale); \\
18. break;
19. BYTECODE_LIST(CALL_GENERATOR);
20. #undef CALL_GENERATOR
21. }
22. Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state, options);
23. return code;
24. }

上述代码中,Bytecode bytecode是枚举变量,源码如下:

// Enumeration of interpreter bytecodes.
enum class Bytecode : uint8_t {
#define DECLARE_BYTECODE(Name, ...) k##Name,
BYTECODE_LIST(DECLARE_BYTECODE)
#undef DECLARE_BYTECODE
#define COUNT_BYTECODE(x, ...) +1
// The COUNT_BYTECODE macro will turn this into kLast = -1 +1 +1... which will
// evaluate to the same value as the last real bytecode.
kLast = -1 BYTECODE_LIST(COUNT_BYTECODE)
#undef COUNT_BYTECODE
};

GenerateBytecodeHandler()的第14行代码:根据bytecode的类型执行对应的case以完成Bytecode handler的初始化。BYTECODE_LIST源码如下:

// The list of bytecodes which are interpreted by the interpreter.
// Format is V(<bytecode>, <accumulator_use>, <operands>).
#define BYTECODE_LIST(V) \\
/* Extended width operands */ \\
V(Wide, AccumulatorUse::kNone) \\
V(ExtraWide, AccumulatorUse::kNone) \\
\\
/* Debug Breakpoints - one for each possible size of unscaled bytecodes */ \\
/* and one for each operand widening prefix bytecode */ \\
V(DebugBreakWide, AccumulatorUse::kReadWrite) \\
V(DebugBreakExtraWide, AccumulatorUse::kReadWrite) \\
V(DebugBreak0, AccumulatorUse::kReadWrite) \\
V(DebugBreak1, AccumulatorUse::kReadWrite, OperandType::kReg) \\
V(DebugBreak2, AccumulatorUse::kReadWrite, OperandType::kReg, \\
OperandType::kReg) \\
V(DebugBreak3, AccumulatorUse::kReadWrite, OperandType::kReg, \\
OperandType::kReg, OperandType::kReg) \\
//省略...................................
//.................................分隔线.......................................
switch (bytecode) {
case Bytecode::kWide: \\
WideAssembler::Generate(&state, operand_scale); \\
break;
case Bytecode::kLdaSmi: \\
LdaSmiAssembler::Generate(&state, operand_scale); \\
break;
//省略...................................
}

通过展开kWide和KLdaSmi可以看到各自的生成函数,图2给出了此时的调用堆栈。

下面讲解LdaSmi的初始化,LdaSmi的初始化函数由宏IGNITION_HANDLER和IGNITION_HANDLER(LdaSmi, InterpreterAssembler)共同组成,展开后的源码如下:

1.    class LdaSmiAssembler : public InterpreterAssembler { 
2. public:
3. explicit LdaSmiAssembler(compiler::CodeAssemblerState* state,
4. Bytecode bytecode, OperandScale scale)
5. : InterpreterAssembler(state, bytecode, scale) {}
6. static void Generate(compiler::CodeAssemblerState* state,
7. OperandScale scale);
8. private:
9. void GenerateImpl();
10. DISALLOW_COPY_AND_ASSIGN(LdaSmiAssembler);
11. };
12. void LdaSmiAssembler::Generate(compiler::CodeAssemblerState* state,
13. OperandScale scale) {
14. LdaSmiAssembler assembler(state, Bytecode::kLdaSmi, scale);
15. state->SetInitialDebugInformation(\"LdaSmi\", __FILE__, __LINE__);
16. assembler.GenerateImpl();
17. }
18. void LdaSmiAssembler::GenerateImpl(){
19. TNode<Smi> smi_int = BytecodeOperandImmSmi(0);
20. SetAccumulator(smi_int);
21. Dispatch();
22. }

上述代码满足case Bytecode::kLdaSmi条件,执行第12行代码Generate();在Generate()中调用GenerateImpl()(第18行代码);第19行代码生成小整数smi_int;第20行代码把smi_int存入累加寄存器。第1行代码InterpreterAssembler的父类InterpreterAssembler实现了很多Bytecode handler的基础功能,源码如下:

TNode<Object> InterpreterAssembler::GetAccumulator() {
DCHECK(Bytecodes::ReadsAccumulator(bytecode_));
accumulator_use_ = accumulator_use_ | AccumulatorUse::kRead;
return TaggedPoisonOnSpeculation(GetAccumulatorUnchecked());
}
//分隔线.................................
void InterpreterAssembler::SetAccumulator(SloppyTNode<Object> value) {
DCHECK(Bytecodes::WritesAccumulator(bytecode_));
accumulator_use_ = accumulator_use_ | AccumulatorUse::kWrite;
accumulator_ = value;
}
//分隔线.................................
TNode<ExternalReference> InterpreterAssembler::DispatchTablePointer() {
if (Bytecodes::MakesCallAlongCriticalPath(bytecode_) && made_call_ &&
(dispatch_table_.value() ==
Parameter(InterpreterDispatchDescriptor::kDispatchTable))) {
dispatch_table_ = ExternalConstant(
ExternalReference::interpreter_dispatch_table_address(isolate()));
}
return dispatch_table_.value();
}

上述代码中GetAccumulator()获取累加器的值;SetAccumulator设置累加器的值;DispatchTablePointer()获取dispatchtable的地址;这些函数的源码在interpreter-assembler.cc文件中。
技术总结
(1) 调试Bytecode handler的方法是在Code GenerateBytecodeHandler()中设置断点;
(2) Bytecode在宏BYTECODELIST中的位置是Bytecode的编号index,index是Bytecode handler在dispatch_table中的下标;
(3) InterpreterAssembler中定义了Bytecode handler的底层功能,CodeAssembler中定义了更底层的原子操作。

好了,今天到这里,下次见。

个人能力有限,有不足与纰漏,欢迎批评指正
微信:qq9123013 备注:v8交流 邮箱:v8blink@outlook.com

赞(0) 打赏
未经允许不得转载:黑客技术网 » 《Chrome V8源码》26.Bytecode Handler,字节码的核心
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏