Reason:fix some fastcall bug

Description:fix some fastcall bug
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I774L6?from=project-issue

Signed-off-by: wupengyong <wupengyong@huawei.com>
Change-Id: Ib6f2b02a25a95d42814042c21bc45390f44c6107
This commit is contained in:
wupengyong 2023-05-23 10:59:56 +08:00
parent 0b104fb672
commit e0134a4d57
13 changed files with 120 additions and 32 deletions

View File

@ -961,11 +961,11 @@ DEF_CALL_SIGNATURE(JSOptimizedCall)
DEF_CALL_SIGNATURE(JSOptimizedFastCall)
{
// 6 : 6 input parameters
// 3 : 3 input parameters
CallSignature jSCall("JSOptimizedFastCall", 0, 3,
ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY());
*callSign = jSCall;
std::array<VariableType, 5> params = { // 5 : 5 input parameters
std::array<VariableType, 3> params = { // 3 : 3 input parameters
VariableType::NATIVE_POINTER(), // glue
VariableType::JS_ANY(), // call target
VariableType::JS_ANY(), // thisobj

View File

@ -120,6 +120,7 @@ void OptimizedCall::IncreaseStackForArguments(ExtendedAssembler *assembler, Regi
// %x1 - actualNumArgs
// %x2 - argV
// %x3 - prevFp
// %x4 - needPushUndefined
//
// * The JSFunctionEntry Frame's structure is illustrated as the following:
// +--------------------------+
@ -138,10 +139,14 @@ void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
Register glueReg(X0);
Register argV(X2);
Register prevFpReg(X3);
Register needPushUndefined(X4);
Register sp(SP);
Register tmpArgV(X7);
Label lJSCallWithArgVAndPushUndefined;
Label lPopFrame;
PushJSFunctionEntryFrame (assembler, prevFpReg);
__ Mov(Register(X6), needPushUndefined);
__ Mov(tmpArgV, argV);
__ Mov(Register(X20), glueReg);
__ Ldr(Register(X2), MemoryOperand(tmpArgV, 0));
@ -149,8 +154,14 @@ void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
__ Ldr(Register(X4), MemoryOperand(tmpArgV, DOUBLE_SLOT_SIZE));
__ Add(tmpArgV, tmpArgV, Immediate(TRIPLE_SLOT_SIZE));
__ Mov(Register(X5), tmpArgV);
__ Cmp(Register(X6), Immediate(1));
__ B(Condition::EQ, &lJSCallWithArgVAndPushUndefined);
__ CallAssemblerStub(RTSTUB_ID(JSCallWithArgV), false);
__ B(&lPopFrame);
__ Bind(&lJSCallWithArgVAndPushUndefined);
__ CallAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushUndefined), false);
__ Bind(&lPopFrame);
__ Mov(Register(X2), Register(X20));
PopJSFunctionEntryFrame(assembler, Register(X2));
__ Ret();
@ -643,7 +654,7 @@ void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Re
Register callField(X9);
__ Ldr(Register(X8), MemoryOperand(boundTarget, JSFunction::METHOD_OFFSET));
__ Ldr(callField, MemoryOperand(Register(X8), Method::CALL_FIELD_OFFSET));
__ Tbnz(callField, MethodLiteral::IsAotCodeBit::START_BIT, &aotCall);
__ Tbz(callField, MethodLiteral::IsAotCodeBit::START_BIT, &slowCall);
__ Bind(&aotCall);
{
// output: glue:x0 argc:x1 calltarget:x2 argv:x3 this:x4 newtarget:x5
@ -1114,7 +1125,7 @@ void OptimizedCall::DeoptHandlerAsm(ExtendedAssembler *assembler)
__ Mov(runtimeId, Immediate(RTSTUB_ID(DeoptHandler)));
__ Stp(runtimeId, argC, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
__ CallAssemblerStub(RTSTUB_ID(CallRuntime), false);
__ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 4: skip runtimeId, argc, depth, shiftLen
__ Add(sp, sp, Immediate(2 * DOUBLE_SLOT_SIZE)); // 2: skip runtimeId, argc, depth, shiftLen
__ CalleeRestore();
Register context(X2);

View File

@ -37,6 +37,7 @@ namespace panda::ecmascript::x64 {
// %rsi - actualNumArgs
// %rdx - argV
// %rcx - prevFp
// %r8 - needPushUndefined
//
// * The JSFunctionEntry Frame's structure is illustrated as the following:
// +--------------------------+
@ -55,16 +56,26 @@ void OptimizedCall::JSFunctionEntry(ExtendedAssembler *assembler)
Register glueReg = rdi;
Register argv = rdx;
Register prevFpReg = rcx;
Register needPushUndefined = r8;
Label lJSCallWithArgVAndPushUndefined;
Label lPopFrame;
PushJSFunctionEntryFrame(assembler, prevFpReg);
__ Movq(argv, rbx);
__ Movq(needPushUndefined, r12);
__ Movq(Operand(rbx, 0), rdx);
__ Movq(Operand(rbx, FRAME_SLOT_SIZE), rcx);
__ Movq(Operand(rbx, DOUBLE_SLOT_SIZE), r8);
__ Addq(TRIPLE_SLOT_SIZE, rbx);
__ Movq(rbx, r9);
__ Cmp(1, r12);
__ Je(&lJSCallWithArgVAndPushUndefined);
__ CallAssemblerStub(RTSTUB_ID(JSCallWithArgV), false);
__ Jmp(&lPopFrame);
__ Bind(&lJSCallWithArgVAndPushUndefined);
__ CallAssemblerStub(RTSTUB_ID(JSCallWithArgVAndPushUndefined), false);
__ Bind(&lPopFrame);
__ Popq(prevFpReg);
__ Addq(FRAME_SLOT_SIZE, rsp); // 8: frame type
__ Popq(rbp);
@ -625,6 +636,7 @@ void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Re
__ Pushq(r10); // push actual arguments
}
JSCallCheck(assembler, rax, &slowCall, &slowCall, &isJsFunc); // jsfunc -> rsi hclassfiled -> rax
__ Jmp(&slowCall);
Register jsfunc = rsi;
Register methodCallField = rcx;
Register method = rdx;
@ -635,7 +647,7 @@ void OptimizedCall::JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Re
__ Mov(Operand(rsi, JSFunctionBase::METHOD_OFFSET), method); // get method
__ Mov(Operand(method, Method::CALL_FIELD_OFFSET), methodCallField); // get call field
__ Btq(MethodLiteral::IsAotCodeBit::START_BIT, methodCallField); // is aot
__ Jb(&aotCall);
__ Jnb(&slowCall);
__ Bind(&aotCall);
{
// output: glue:rdi argc:rsi calltarget:rdx argv:rcx this:r8 newtarget:r9

View File

@ -443,7 +443,8 @@ JSTaggedValue EcmaVM::FastCallAot(size_t actualNumArgs, JSTaggedType *args, cons
return res;
}
JSTaggedValue EcmaVM::ExecuteAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp)
JSTaggedValue EcmaVM::ExecuteAot(size_t actualNumArgs, JSTaggedType *args,
const JSTaggedType *prevFp, bool needPushUndefined)
{
INTERPRETER_TRACE(thread_, ExecuteAot);
auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_JSFunctionEntry);
@ -452,7 +453,8 @@ JSTaggedValue EcmaVM::ExecuteAot(size_t actualNumArgs, JSTaggedType *args, const
auto res = reinterpret_cast<JSFunctionEntryType>(entry)(thread_->GetGlueAddr(),
actualNumArgs,
args,
reinterpret_cast<uintptr_t>(prevFp));
reinterpret_cast<uintptr_t>(prevFp),
needPushUndefined);
return res;
}

View File

@ -530,7 +530,8 @@ public:
return quickFixManager_;
}
JSTaggedValue ExecuteAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp);
JSTaggedValue ExecuteAot(size_t actualNumArgs, JSTaggedType *args,
const JSTaggedType *prevFp, bool needPushUndefined);
JSTaggedValue FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp);

View File

@ -817,7 +817,7 @@ JSTaggedValue EcmaInterpreter::GeneratorReEnterAot(JSThread *thread, JSHandle<Ge
args[1] = genObject.GetRawData();
args[2] = context->GetThis().GetRawData(); // 2: this
const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
auto res = thread->GetEcmaVM()->ExecuteAot(method->GetNumArgs(), args.data(), prevFp);
auto res = thread->GetEcmaVM()->ExecuteAot(method->GetNumArgs(), args.data(), prevFp, false);
return res;
}

View File

@ -65,4 +65,47 @@ EcmaRuntimeCallInfo* EcmaInterpreter::NewRuntimeCallInfo(
thread->SetCurrentSPFrame(newSp);
return ecmaRuntimeCallInfo;
}
EcmaRuntimeCallInfo* EcmaInterpreter::ReBuildRuntimeCallInfo(JSThread *thread, EcmaRuntimeCallInfo* info,
uint32_t numArgs, bool needCheckStack)
{
JSTaggedValue func = info->GetFunctionValue();
JSTaggedValue newTarget = info->GetNewTargetValue();
JSTaggedValue thisObj = info->GetThisValue();
JSTaggedType *currentSp = reinterpret_cast<JSTaggedType *>(info);
InterpretedEntryFrame *currentEntryState = InterpretedEntryFrame::GetFrameFromSp(currentSp);
JSTaggedType *prevSp = currentEntryState->base.prev;
uint32_t actualArgc = info->GetArgsNumber();
std::vector<JSTaggedType> args(actualArgc);
for (uint32_t i = 0; i < actualArgc; i++) {
args[i] = info->GetCallArgValue(actualArgc - i - 1).GetRawData();
}
currentSp += (info->GetArgsNumber() + NUM_MANDATORY_JSFUNC_ARGS + 2); // 2: include thread_ and numArgs_
if (needCheckStack && UNLIKELY(thread->DoStackOverflowCheck(currentSp - numArgs - NUM_MANDATORY_JSFUNC_ARGS))) {
return nullptr;
}
ASSERT(numArgs > actualArgc);
for (uint32_t i = 0; i < (numArgs - actualArgc); i++) {
*(--currentSp) = JSTaggedValue::VALUE_UNDEFINED;
}
for (uint32_t i = 0; i < actualArgc; i++) {
*(--currentSp) = args[i];
}
*(--currentSp) = thisObj.GetRawData();
*(--currentSp) = newTarget.GetRawData();
*(--currentSp) = func.GetRawData();
*(--currentSp) = numArgs + NUM_MANDATORY_JSFUNC_ARGS;
*(--currentSp) = ToUintPtr(thread);
EcmaRuntimeCallInfo *ecmaRuntimeCallInfo = reinterpret_cast<EcmaRuntimeCallInfo *>(currentSp);
InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(currentSp);
entryState->base.type = FrameType::INTERPRETER_ENTRY_FRAME;
entryState->base.prev = prevSp;
entryState->pc = nullptr;
thread->SetCurrentSPFrame(currentSp);
return ecmaRuntimeCallInfo;
}
} // namespace panda::ecmascript

View File

@ -44,6 +44,8 @@ public:
static EcmaRuntimeCallInfo* NewRuntimeCallInfo(
JSThread *thread, JSHandle<JSTaggedValue> func, JSHandle<JSTaggedValue> thisObj,
JSHandle<JSTaggedValue> newTarget, uint32_t numArgs, bool needCheckStack = true);
static EcmaRuntimeCallInfo* ReBuildRuntimeCallInfo(
JSThread *thread, EcmaRuntimeCallInfo* info, uint32_t numArgs, bool needCheckStack = true);
static inline JSTaggedValue GeneratorReEnterInterpreter(JSThread *thread, JSHandle<GeneratorContext> context);
static inline JSTaggedValue GeneratorReEnterAot(JSThread *thread, JSHandle<GeneratorContext> context);
#ifndef EXCLUDE_C_INTERPRETER

View File

@ -233,16 +233,7 @@ JSTaggedValue InterpreterAssembly::Execute(EcmaRuntimeCallInfo *info)
}
return thread->GetException();
}
const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
JSTaggedValue res;
if (method->IsFastCall()) {
JSTaggedType *stackArgs = info->GetArgs();
stackArgs[1] = stackArgs[0];
res = thread->GetEcmaVM()->FastCallAot(argc, stackArgs + 1, prevFp);
} else {
res = thread->GetEcmaVM()->ExecuteAot(argc, info->GetArgs(), prevFp);
}
JSTaggedValue res = JSFunction::InvokeOptimizedEntrypoint(thread, func, info);
const JSTaggedType *curSp = thread->GetCurrentSPFrame();
InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(curSp);
JSTaggedType *prevSp = entryState->base.prev;

View File

@ -344,7 +344,7 @@ JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<J
args[2] = thisArg.GetTaggedValue().GetRawData(); // 2: this
// do not modify this log to INFO, this will call many times
LOG_ECMA(DEBUG) << "start to execute aot entry: " << entryPoint;
res = thread->GetEcmaVM()->ExecuteAot(actualNumArgs, args.data(), prevFp);
res = thread->GetEcmaVM()->ExecuteAot(actualNumArgs, args.data(), prevFp, false);
}
if (thread->HasPendingException()) {
return thread->GetException();
@ -352,6 +352,28 @@ JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<J
return res;
}
JSTaggedValue JSFunction::InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> func,
EcmaRuntimeCallInfo *info)
{
Method *method = func->GetCallTarget();
JSTaggedValue resultValue;
uint32_t numArgs = method->GetNumArgsWithCallField();
bool needPushUndefined = numArgs > info->GetArgsNumber();
const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
if (method->IsFastCall()) {
if (needPushUndefined) {
info = EcmaInterpreter::ReBuildRuntimeCallInfo(thread, info, numArgs);
}
JSTaggedType *stackArgs = info->GetArgs();
stackArgs[1] = stackArgs[0];
resultValue = thread->GetEcmaVM()->FastCallAot(info->GetArgsNumber(), stackArgs + 1, prevFp);
} else {
resultValue = thread->GetEcmaVM()->ExecuteAot(info->GetArgsNumber(),
info->GetArgs(), prevFp, needPushUndefined);
}
return resultValue;
}
// [[Construct]]
JSTaggedValue JSFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
{
@ -378,14 +400,7 @@ JSTaggedValue JSFunction::ConstructInternal(EcmaRuntimeCallInfo *info)
info->SetThis(obj.GetTaggedValue());
Method *method = func->GetCallTarget();
if (method->IsAotWithCallField() && func->IsClassConstructor()) {
const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
if (method->IsFastCall()) {
JSTaggedType *stackArgs = info->GetArgs();
stackArgs[1] = stackArgs[0];
resultValue = thread->GetEcmaVM()->FastCallAot(info->GetArgsNumber(), stackArgs + 1, prevFp);
} else {
resultValue = thread->GetEcmaVM()->ExecuteAot(info->GetArgsNumber(), info->GetArgs(), prevFp);
}
resultValue = InvokeOptimizedEntrypoint(thread, func, info);
const JSTaggedType *curSp = thread->GetCurrentSPFrame();
InterpretedEntryFrame *entryState = InterpretedEntryFrame::GetFrameFromSp(curSp);
JSTaggedType *prevSp = entryState->base.prev;

View File

@ -95,6 +95,8 @@ public:
static JSTaggedValue Invoke(EcmaRuntimeCallInfo *info, const JSHandle<JSTaggedValue> &key);
static JSTaggedValue InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> mainFunc,
JSHandle<JSTaggedValue> &thisArg, std::string_view entryPoint);
static JSTaggedValue InvokeOptimizedEntrypoint(JSThread *thread, JSHandle<JSFunction> func,
EcmaRuntimeCallInfo *info);
// 9.2.2[[Construct]](argumentsList, newTarget)
// 9.3.2[[Construct]](argumentsList, newTarget)
static JSTaggedValue ConstructInternal(EcmaRuntimeCallInfo *info);

View File

@ -2463,7 +2463,7 @@ JSTaggedValue RuntimeStubs::RuntimeOptConstructGeneric(JSThread *thread, JSHandl
uint32_t preArgsSize = preArgs->IsUndefined() ? 0 : JSHandle<TaggedArray>::Cast(preArgs)->GetLength();
const uint32_t argsCount = args->GetLength();
const uint32_t size = preArgsSize + argsCount;
uint32_t size = preArgsSize + argsCount;
CVector<JSTaggedType> values;
Method *method = ctor->GetCallTarget();
bool isAotMethod = method->IsAotWithCallField();
@ -2498,11 +2498,20 @@ JSTaggedValue RuntimeStubs::RuntimeOptConstructGeneric(JSThread *thread, JSHandl
}
JSTaggedValue resultValue;
if (isAotMethod && ctor->IsClassConstructor()) {
uint32_t numArgs = ctor->GetCallTarget()->GetNumArgsWithCallField();
bool needPushUndefined = numArgs > size;
const JSTaggedType *prevFp = thread->GetLastLeaveFrame();
if (ctor->GetCallTarget()->IsFastCall()) {
if (needPushUndefined) {
values.reserve(numArgs + NUM_MANDATORY_JSFUNC_ARGS - 1);
for (uint32_t i = size; i < numArgs; i++) {
values.emplace_back(JSTaggedValue::VALUE_UNDEFINED);
}
size = numArgs;
}
resultValue = thread->GetEcmaVM()->FastCallAot(size, values.data(), prevFp);
} else {
resultValue = thread->GetEcmaVM()->ExecuteAot(size, values.data(), prevFp);
resultValue = thread->GetEcmaVM()->ExecuteAot(size, values.data(), prevFp, needPushUndefined);
}
} else {
ctor->GetCallTarget()->SetAotCodeBit(false); // if Construct is not ClassConstructor, don't run aot

View File

@ -38,7 +38,7 @@ class GeneratorContext;
struct EcmaRuntimeCallInfo;
using JSFunctionEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, const JSTaggedType argV[],
uintptr_t prevFp);
uintptr_t prevFp, bool needPushUndefined);
using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, const JSTaggedType argV[],
uintptr_t prevFp);