国科大高级操作系统教程大作业——OpenHarmony RISC-V移植——更新中

文章讲述了在方舟运行时环境中,针对aarch64和x64平台的PushCallThisRangeAndDispatch等函数的移植过程,以及如何在riscv64上实现相似功能。内容涉及函数介绍、路径、代码解析和目标比较等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、 任务概要

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 目标

比较在 aarch64 x64 同名函数,然后实现 riscv的同名函数 适配

二、粗读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类中的成员函数PushCallThisRangeAndDispatchAsmInterpreterCall是一个类,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显示未找到定义,我该信谁呢?

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值