一、 任务概要
1.1 要移植的函数
PushCallThisRangeAndDispatch
PushCallRangeAndDispatch
PushCallNewAndDispatch
PushCallArgs3AndDispatch
PushCallArgs2AndDispatch
PushCallArg1AndDispatch
PushCallArg0AndDispatch
PushCallThisArg0AndDispatch
PushCallThisArg1AndDispatch
PushCallThisArgs2AndDispatch
PushCallThisArgs3AndDispatch
1.2 函数介绍
他们都是跳转函数,作用:
1.3 函数路径
方舟运行时下载链接
https://download.csdn.net/download/weixin_44357071/88637990
1.3.1 代码介绍
方舟ArkTS运行时(ARK TypeScript Runtime)是OpenHarmony上ArkTS应用使用的运行时。包含ArkTS/JS对象的分配器以及垃圾回收器(GC)、符合ECMAScript规范的标准库、用于运行ARK前端组件生成的方舟字节码(ARK Bytecode简称abc)的解释器、用于加速的内联缓存、静态类型编译器、运行时的C++/C函数接口(NAPI)等模块(gitee上面的废话,不影响作业进行)
1.3.2 aarch64
aarch64(也称为ARM64)是一种处理器架构,属于ARM(Advanced RISC Machines)架构家族的一部分
1.3.3 x64
x64(也称为x86_64、AMD64或Intel 64)是一种64位的处理器架构,广泛应用于个人计算机和服务器领域。它是x86架构的扩展,兼容32位的x86指令集,同时引入了新的64位指令集。
1.4 目标
二、粗读PushCallThisRangeAndDispatch
2.1函数声明和定义和猜测意义
void AsmInterpreterCall::PushCallThisRangeAndDispatch(ExtendedAssembler *assembler)
{
__ BindAssemblerStub(RTSTUB_ID(PushCallThisRangeAndDispatch));
JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_WITH_ARGV);
}
接下来通过函数或者变量的名称猜测一下代码意义。
ASM:这可能是"Assembly"的简写,指代汇编语言(Assembly Language)。汇编语言是一种低级编程语言,与特定的计算机体系结构紧密相关,用于直接操作硬件和底层计算机指令
Interperter:这个词通常指解释器(Interpreter),是一种将源代码逐行解释执行的程序。解释器会逐行读取源代码,并将其转换为可执行的指令或操作。
Call:这个词通常指函数调用(Function Call),表示在程序中调用一个函数或子程序。
Push:这个词通常指将数据或元素推入栈(Stack)中。在编程中,栈是一种用于存储和管理数据的数据结构,遵循后进先出(LIFO)的原则。
Range:这个词通常指代范围或区间。在编程中,范围可以表示一系列连续的值或索引
Dispatch:这个词通常指派发(Dispatch),特别是在面向对象编程中。派发是根据对象类型或其他条件,决定执行哪个方法或函数的过程。
PushCallThisRangeAndDispatch:将某个值或对象推入栈中,然后根据当前对象和范围来派发执行相应的方法或函数。
Extended:这个词通常表示扩展或延伸。在编程中,扩展可以指添加额外的功能、增加支持的操作或提供更多选项。
Assembler:这个词通常指汇编器(Assembler),是一种将汇编语言代码转换为机器指令的程序。汇编器是一种低级程序,用于直接操作计算机硬件和底层指令。
ExtendedAssembler:可能用途是一种扩展的或拓展功能的汇编器。它可能提供了额外的功能或选项,以增强汇编语言的编程能力或支持更高级的操作。
Bind /baɪnd/ :这个词通常指绑定或关联。在编程中,绑定可以表示将一个变量、函数或操作与另一个对象或上下文关联起来。
Stub:这个词通常指存根(Stub),是一个占位或临时实现,用于代替或模拟真正的实现。
BindAssemblerStub:可能用途是将一个汇编器存根(Assembler Stub)与名称为PushCallRangeAndDispatch
的函数或操作进行绑定。这可能是为了将汇编器存根与特定的函数或操作关联,以便在运行时进行调用或执行。
RTSTUB_ID:猜测RT是Return的简写,函数的作用是返回存根的ID。
JS:这个词通常表示JavaScript,一种广泛用于前端和后端开发的编程语言。此项目就是华为的方舟编译器运行时项目源码,它目前主要支持的语言是JavaScript、TypeScript和Java2。
方舟编译器会把JavaScript、TypeScript和其他语言编译为方舟字节码,运行时直接运行方舟字节码。这样可以提高应用的性能和安全性,同时也可以实现多语言的互操作。
所以猜测
Common:这个词通常表示通用或共享的。在编程中,"common"可以指共享的代码、数据结构或算法。
Entry:这个词通常指入口(Entry),表示程序的起始点或执行的入口位置。
JSCallCommonEntry:可能是指JavaScript中的一个通用函数调用入口。它可能作为一个标准入口点,用于处理函数调用或执行某些常见的操作。
JSCallMode:调用JS函数的模式和方法
2.2 AsmInterpreterCall::PushCallThisRangeAndDispatch
在这段代码中,::
用于指定AsmInterpreterCall
类中的成员函数PushCallThisRangeAndDispatch
。AsmInterpreterCall
是一个类,PushCallThisRangeAndDispatch
是该类的成员函数。
2.2.1 class AsmInterpreterCall : public CommonCall
这段代码是一个C++类的定义,它声明了一个名为AsmInterpreterCall
的类,该类继承自CommonCall
类。
CommonCall
是一个基类(或父类),而AsmInterpreterCall
是一个派生类(或子类)。派生类可以继承基类的属性和方法,并可以在此基础上添加自己的特定功能。
2.3 void AsmInterpreterCall::PushCallThisRangeAndDispatch(ExtendedAssembler *assembler)
这一段代码说明这个函数声明接下来的的函数定义,是对AsmInterpreterCall类里面PushCallThisRangeAndDispatch函数进行定义,函数的参数有ExtendedAssembler 这个类指针,用 *assemblerl来接收
2.3.1 class ExtendedAssembler : public AssemblerAarch64
ExtendedAssembler是继承自public AssemblerAarch64的类
2.4 __ (是双下划线)
#define __ assembler->
这个宏定义将双下划线定义为assembler类加上箭头操作符
在 C++ 中,->
被称为箭头操作符(Arrow Operator)。箭头操作符通常与指针一起使用,用于通过指针访问成员(变量或函数)
2.5 __ BindAssemblerStub(int id);
写全了其实相当于assembler-> BindAssemblerStub();
即使用assembler类下的成员函数BindAssemblerStub();但是又因为前面的传参,
AsmInterpreterCall::PushCallThisRangeAndDispatch(ExtendedAssembler *assembler)
所以实际上assembler是 ExtendedAssembler的一个实例化,所以
__ BindAssemblerStub(int id);的函数定义如下:
void ExtendedAssembler::BindAssemblerStub(int id)
{
Label *target = module_->GetFunctionLabel(id);
Bind(target);
auto callSigns = module_->GetCSigns();
auto cs = callSigns[id];
printf("in BindAssemblerStub GetName:%s\n", callSigns[id]->GetName().c_str());
isGhcCallingConv_ = cs->GetCallConv() ==
CallSignature::CallConv::GHCCallConv;
}
2.6 AsmInterpreterCall::JSCallCommonEntry
函数定义如下
void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode)
{
Label stackOverflow;
Register glueRegister = __ GlueRegister();
Register fpRegister = __ AvailableRegister1();
Register currentSlotRegister = __ AvailableRegister3();
Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGC);
if (!kungfu::AssemblerModule::IsJumpToCallCommonEntry(mode)) {
__ PushFpAndLr();
}
// save fp
__ Mov(fpRegister, Register(SP));
__ Mov(currentSlotRegister, Register(SP));
{
// Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
[[maybe_unused]] TempRegister1Scope scope(assembler);
Register tempRegister = __ TempRegister1();
__ Ldr(tempRegister, MemoryOperand(glueRegister, JSThread::GlueData::GetCurrentContextOffset(false)));
__ Ldr(tempRegister, MemoryOperand(tempRegister, 0));
__ Mov(Register(SP), tempRegister);
}
Register declaredNumArgsRegister = __ AvailableRegister2();
GetDeclaredNumArgsFromCallField(assembler, callFieldRegister, declaredNumArgsRegister);
Label slowPathEntry;
Label fastPathEntry;
Label pushCallThis;
auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
if (argc >= 0) {
__ Cmp(declaredNumArgsRegister, Immediate(argc));
} else {
__ Cmp(declaredNumArgsRegister, argcRegister);
}
__ B(Condition::NE, &slowPathEntry);
__ Bind(&fastPathEntry);
JSCallCommonFastPath(assembler, mode, &pushCallThis, &stackOverflow);
__ Bind(&pushCallThis);
PushCallThis(assembler, mode, &stackOverflow);
__ Bind(&slowPathEntry);
JSCallCommonSlowPath(assembler, mode, &fastPathEntry, &pushCallThis, &stackOverflow);
__ Bind(&stackOverflow);
if (kungfu::AssemblerModule::IsJumpToCallCommonEntry(mode)) {
__ Mov(Register(SP), fpRegister);
[[maybe_unused]] TempRegister1Scope scope(assembler);
Register temp = __ TempRegister1();
// only glue and acc are useful in exception handler
if (glueRegister.GetId() != X19) {
__ Mov(Register(X19), glueRegister);
}
Register acc(X23);
__ Mov(acc, Immediate(JSTaggedValue::VALUE_EXCEPTION));
Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
// Reload pc to make sure stack trace is right
__ Mov(temp, callTargetRegister);
__ Ldr(Register(X20), MemoryOperand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
// Reload constpool and profileInfo to make sure gc map work normally
__ Ldr(Register(X22), MemoryOperand(methodRegister, Method::PROFILE_TYPE_INFO_OFFSET));
__ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET));
__ Mov(temp, kungfu::BytecodeStubCSigns::ID_ThrowStackOverflowException);
__ Add(temp, glueRegister, Operand(temp, UXTW, 3)); // 3: bc * 8
__ Ldr(temp, MemoryOperand(temp, JSThread::GlueData::GetBCStubEntriesOffset(false)));
__ Br(temp);
} else {
[[maybe_unused]] TempRegister1Scope scope(assembler);
Register temp = __ TempRegister1();
ThrowStackOverflowExceptionAndReturn(assembler, glueRegister, fpRegister, temp);
}
}
2.7 JSCallMode
畅哥说是个枚举,还没来得及看,代码如下
enum class JSCallMode : uintptr_t {
CALL_ARG0 = 0,
CALL_ARG1,
CALL_ARG2,
CALL_ARG3,
CALL_THIS_ARG0,
CALL_THIS_ARG1,
CALL_THIS_ARG2,
CALL_THIS_ARG3,
CALL_WITH_ARGV,
CALL_THIS_WITH_ARGV,
CALL_CONSTRUCTOR_WITH_ARGV,
DEPRECATED_CALL_ARG0,
DEPRECATED_CALL_ARG1,
DEPRECATED_CALL_ARG2,
DEPRECATED_CALL_ARG3,
DEPRECATED_CALL_WITH_ARGV,
DEPRECATED_CALL_THIS_WITH_ARGV,
DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV,
CALL_GETTER,
CALL_SETTER,
CALL_THIS_ARG3_WITH_RETURN,
CALL_THIS_ARGV_WITH_RETURN,
CALL_ENTRY,
CALL_GENERATOR,
CALL_FROM_AOT,
};
三、确认riscv64中需要写的函数
用分析aarch64的思路,分析一遍riscv64。首先,咱们负责的riscv64部分的函数很整齐,都是一个套路,如图所示
3.1 函数声明和定义
void AsmInterpreterCall::PushCallThisRangeAndDispatch(ExtendedAssembler *assembler)
{
assembler->BindAssemblerStub(RTSTUB_ID(PushCallThisRangeAndDispatch));
uint8_t* buffer = assembler->getBuffer();
printf("%s\n", buffer);
}
3.2 void AsmInterpreterCall::PushCallThisRangeAndDispatch
(ExtendedAssembler *assembler)
可以看到AsmInterpreterCall这个类里面定义了咱们要完成的函数们,而AsmInterpreterCall又继承自CommonCall这个类,都做了定义,说明我们只需要关心PushCallThisRangeAndDispatch的实现即可,不用给AsmInterpreterCall类补刀
ExtendedAssembler的话先不急,等待通知
另一个文件夹下面的.cpp文件能通过::符号来让riscv下面的文件使用吗
还是我应该在extended assembler下面去找这个函数的定义,在那里vscode显示未找到定义,我该信谁呢?