mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2025-03-01 08:48:03 +00:00
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:
parent
0b104fb672
commit
e0134a4d57
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user