!4612 Optimize aot stackoverflow

Merge pull request !4612 from wpy111/master
This commit is contained in:
openharmony_ci 2023-08-22 06:38:41 +00:00 committed by Gitee
commit c2214d0e5f
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
11 changed files with 111 additions and 68 deletions

View File

@ -64,7 +64,7 @@ void SlowPathLowering::CallRuntimeLowering()
LowerTypedFastCall(gate);
break;
case OpCode::CHECK_SAFEPOINT_AND_STACKOVER:
LowerCheckSafePointAndStackOver(gate);
LowerCheckSafePointAndStackOverflow(gate);
break;
case OpCode::GET_ENV:
LowerGetEnv(gate);
@ -3139,31 +3139,23 @@ void SlowPathLowering::LowerTypedFastCall(GateRef gate)
ReplaceHirWithPendingException(gate, state, result, result);
}
void SlowPathLowering::LowerCheckSafePointAndStackOver(GateRef gate)
void SlowPathLowering::LowerCheckSafePointAndStackOverflow(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
Label slowPath(&builder_);
Label dispatch(&builder_);
Label checkStackOver(&builder_);
Label checkStackOverflow(&builder_);
Label stackOverflow(&builder_);
GateRef stackLimit = builder_.Load(VariableType::INT64(), glue_,
builder_.IntPtr(JSThread::GlueData::GetStackLimitOffset(builder_.GetCompilationConfig()->Is32Bit())));
GateRef interruptsFlag = builder_.Load(VariableType::INT8(), glue_,
builder_.IntPtr(JSThread::GlueData::GetInterruptVectorOffset(builder_.GetCompilationConfig()->Is32Bit())));
GateRef stackLimitOffset =
builder_.IntPtr(JSThread::GlueData::GetStackLimitOffset(builder_.GetCompilationConfig()->Is32Bit()));
GateRef stackLimit = builder_.Load(VariableType::INT64(), glue_, stackLimitOffset);
GateRef spValue = builder_.ReadSp();
builder_.Branch(builder_.Int8Equal(interruptsFlag,
builder_.Int8(VmThreadControl::VM_NEED_SUSPENSION)), &slowPath, &checkStackOver);
builder_.Bind(&slowPath);
builder_.Branch(builder_.Int64LessThanOrEqual(spValue, stackLimit), &checkStackOverflow, &dispatch);
builder_.Bind(&checkStackOverflow);
{
LowerCallRuntime(glue_, RTSTUB_ID(CheckSafePoint), {}, true);
builder_.Jump(&checkStackOver);
}
builder_.Bind(&checkStackOver);
{
builder_.Branch(builder_.Int64LessThanOrEqual(spValue, stackLimit), &stackOverflow, &dispatch);
GateRef res = LowerCallRuntime(glue_, RTSTUB_ID(CheckSafePointAndStackOverflow), {}, true);
builder_.Branch(builder_.TaggedIsUndefined(res), &dispatch, &stackOverflow);
builder_.Bind(&stackOverflow);
{
GateRef res = LowerCallRuntime(glue_, RTSTUB_ID(ThrowStackOverflowException), {}, true);
builder_.Return(res);
}
}

View File

@ -299,7 +299,7 @@ private:
void LowerConstruct(GateRef gate);
void LowerTypedCall(GateRef gate);
void LowerTypedFastCall(GateRef gate);
void LowerCheckSafePointAndStackOver(GateRef gate);
void LowerCheckSafePointAndStackOverflow(GateRef gate);
void LowerNotifyConcurrentResult(GateRef gate);
void LowerGetEnv(GateRef gate);
void DeleteLoopExit(GateRef gate);

View File

@ -138,7 +138,8 @@ void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler, JSCallM
// 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::GetStackLimitOffset(false)));
__ Ldr(tempRegister, MemoryOperand(glueRegister, JSThread::GlueData::GetCurrentContextOffset(false)));
__ Ldr(tempRegister, MemoryOperand(tempRegister, 0));
__ Mov(Register(SP), tempRegister);
}
@ -483,7 +484,8 @@ void AsmInterpreterCall::CallNativeWithArgv(ExtendedAssembler *assembler, bool c
__ Mov(currentSlotRegister, spRegister);
// Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
__ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
__ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetCurrentContextOffset(false)));
__ Ldr(temp, MemoryOperand(temp, 0));
__ Mov(Register(SP), temp);
__ Mov(opArgc, argc);
@ -997,7 +999,8 @@ void AsmInterpreterCall::GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *as
__ Mov(fpRegister, spRegister);
__ Mov(currentSlotRegister, spRegister);
// Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
__ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
__ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetCurrentContextOffset(false)));
__ Ldr(temp, MemoryOperand(temp, 0));
__ Mov(Register(SP), temp);
// push context regs
__ Ldr(nRegsRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_NREGS_OFFSET));

View File

@ -140,6 +140,9 @@ void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue,
__ Sub(op, currentSlot, Operand(op, UXTX, 0));
__ Cmp(op, Operand(numArgs, LSL, 3)); // 3: each args occupies 8 bytes
__ B(Condition::GT, &skipThrow);
__ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetInterruptVectorOffset(false)));
__ Tbnz(op, JSThread::CheckSafePointBit::START_BIT, &skipThrow);
// CheckSafePointBit is false, is actual stack over flow
__ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetAllowCrossThreadExecutionOffset(false)));
__ Cbz(op, stackOverflow);
__ Bind(&skipThrow);

View File

@ -107,6 +107,7 @@ void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue,
{
Register temp1 = op1;
Register temp2 = op2;
Label skipThrow;
if (op1 == op2) {
// reuse glue as an op register for temporary
__ Pushq(glue);
@ -118,10 +119,17 @@ void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue,
__ Movl(numArgs, temp1);
__ Shlq(3, temp1); // 3: each arg occupies 8 bytes
__ Cmpq(temp1, temp2);
__ Jg(&skipThrow);
if (op1 == op2) {
__ Popq(glue);
}
__ Movq(Operand(glue, JSThread::GlueData::GetInterruptVectorOffset(false)), temp1);
__ Btq(JSThread::CheckSafePointBit::START_BIT, temp1);
__ Jnb(stackOverflow); // CheckSafePointBit is false, is actual stack over flow
__ Bind(&skipThrow);
if (op1 == op2) {
__ Popq(glue);
}
__ Jle(stackOverflow);
}
#undef __
} // namespace panda::ecmascript::x64

View File

@ -407,7 +407,8 @@ private:
bool LoadAOTFiles(const std::string &aotFileName);
NO_MOVE_SEMANTIC(EcmaContext);
NO_COPY_SEMANTIC(EcmaContext);
uint64_t stackLimit_ {0};
uint64_t stackStart_ {0};
JSThread *thread_ {nullptr};
EcmaVM *vm_ {nullptr};
@ -469,8 +470,6 @@ private:
JSTaggedType *leaveFrame_ {nullptr};
JSTaggedType *lastFp_ {nullptr};
JSTaggedType *frameBase_ {nullptr};
uint64_t stackStart_ {0};
uint64_t stackLimit_ {0};
PropertiesCache *propertiesCache_ {nullptr};
GlobalEnvConstants globalConst_;
// Join Stack

View File

@ -216,7 +216,7 @@ void JSThread::Iterate(const RootVisitor &visitor, const RootRangeVisitor &range
visitor(Root::ROOT_VM, ObjectSlot(ToUintPtr(&glueData_.exception_)));
}
EcmaContext *tempContext = currentContext_;
EcmaContext *tempContext = glueData_.currentContext_;
for (EcmaContext *context : contexts_) {
// visit stack roots
SwitchCurrentContext(context, true);
@ -570,9 +570,9 @@ void JSThread::PushContext(EcmaContext *context)
const_cast<Heap *>(vm_->GetHeap())->WaitAllTasksFinished();
contexts_.emplace_back(context);
if (!currentContext_) {
if (!glueData_.currentContext_) {
// The first context in ecma vm.
currentContext_ = context;
SetCurrentEcmaContext(context);
context->SetFramePointers(const_cast<JSTaggedType *>(GetCurrentSPFrame()),
const_cast<JSTaggedType *>(GetLastLeaveFrame()),
const_cast<JSTaggedType *>(GetLastFp()));
@ -596,27 +596,33 @@ void JSThread::PushContext(EcmaContext *context)
void JSThread::PopContext()
{
contexts_.pop_back();
currentContext_ = contexts_.back();
SwitchCurrentContext(contexts_.back());
}
void JSThread::SwitchCurrentContext(EcmaContext *currentContext, bool isInIterate)
{
ASSERT(std::count(contexts_.begin(), contexts_.end(), currentContext));
currentContext_->SetFramePointers(const_cast<JSTaggedType *>(GetCurrentSPFrame()),
// If glueData_.currentContext_ == currentContext, don't need switch context
if (glueData_.currentContext_ == currentContext) {
return;
}
glueData_.currentContext_->SetFramePointers(const_cast<JSTaggedType *>(GetCurrentSPFrame()),
const_cast<JSTaggedType *>(GetLastLeaveFrame()),
const_cast<JSTaggedType *>(GetLastFp()));
currentContext_->SetFrameBase(glueData_.frameBase_);
currentContext_->SetStackLimit(GetStackLimit());
currentContext_->SetStackStart(GetStackStart());
currentContext_->SetGlobalEnv(GetGlueGlobalEnv());
currentContext_->GetGlobalEnv()->SetJSGlobalObject(this, glueData_.globalObject_);
glueData_.currentContext_->SetFrameBase(glueData_.frameBase_);
glueData_.currentContext_->SetGlobalEnv(GetGlueGlobalEnv());
glueData_.currentContext_->GetGlobalEnv()->SetJSGlobalObject(this, glueData_.globalObject_);
SetCurrentSPFrame(currentContext->GetCurrentFrame());
SetLastLeaveFrame(currentContext->GetLeaveFrame());
SetLastFp(currentContext->GetLastFp());
glueData_.frameBase_ = currentContext->GetFrameBase();
glueData_.stackLimit_ = currentContext->GetStackLimit();
if (HasCheckSafePoint()) {
// If CheckSafePointBit is true, stackLimit_ need to be stackStart_ like SetCheckSafePointStatus
glueData_.stackLimit_ = currentContext->GetStackStart();
} else {
glueData_.stackLimit_ = currentContext->GetStackLimit();
}
glueData_.stackStart_ = currentContext->GetStackStart();
if (!currentContext->GlobalEnvIsHole()) {
SetGlueGlobalEnv(*(currentContext->GetGlobalEnv()));
@ -627,7 +633,7 @@ void JSThread::SwitchCurrentContext(EcmaContext *currentContext, bool isInIterat
glueData_.globalConst_ = const_cast<GlobalEnvConstants *>(currentContext->GlobalConstants());
}
currentContext_ = currentContext;
SetCurrentEcmaContext(currentContext);
}
bool JSThread::EraseContext(EcmaContext *context)
@ -636,7 +642,7 @@ bool JSThread::EraseContext(EcmaContext *context)
bool isCurrentContext = false;
auto iter = std::find(contexts_.begin(), contexts_.end(), context);
if (*iter == context) {
if (currentContext_ == context) {
if (glueData_.currentContext_ == context) {
isCurrentContext = true;
}
contexts_.erase(iter);
@ -650,7 +656,7 @@ bool JSThread::EraseContext(EcmaContext *context)
PropertiesCache *JSThread::GetPropertiesCache() const
{
return currentContext_->GetPropertiesCache();
return glueData_.currentContext_->GetPropertiesCache();
}
const GlobalEnvConstants *JSThread::GetFirstGlobalConst() const
@ -667,4 +673,19 @@ bool JSThread::IsAllContextsInitialized() const
}
return true;
}
void JSThread::ResetCheckSafePointStatus()
{
ASSERT(static_cast<uint8_t>(glueData_.interruptVector_ & CHECKSAFEPOINT_FLAG) <= 1);
CheckSafePointBit::Set(false, &glueData_.interruptVector_);
ASSERT(glueData_.currentContext_ != nullptr);
SetStackLimit(glueData_.currentContext_->GetStackLimit());
}
void JSThread::SetCheckSafePointStatus()
{
ASSERT(static_cast<uint8_t>(glueData_.interruptVector_ & CHECKSAFEPOINT_FLAG) <= 1);
CheckSafePointBit::Set(true, &glueData_.interruptVector_);
SetStackLimit(GetStackStart());
}
} // namespace panda::ecmascript

View File

@ -190,6 +190,7 @@ public:
static constexpr int PGO_PROFILER_BITFIELD_START = 16;
static constexpr int BOOL_BITFIELD_NUM = 1;
static constexpr uint32_t RESERVE_STACK_SIZE = 128;
static constexpr uint64_t CHECKSAFEPOINT_FLAG = 0xFF;
using MarkStatusBits = BitField<MarkStatus, 0, CONCURRENT_MARKING_BITFIELD_NUM>;
using CheckSafePointBit = BitField<bool, 0, BOOL_BITFIELD_NUM>;
using VMNeedSuspensionBit = BitField<bool, CHECK_SAFEPOINT_BITFIELD_NUM, BOOL_BITFIELD_NUM>;
@ -542,16 +543,9 @@ public:
return reinterpret_cast<JSThread *>(glue - GetGlueDataOffset());
}
void SetCheckSafePointStatus()
bool HasCheckSafePoint() const
{
ASSERT(static_cast<uint8_t>(glueData_.interruptVector_ & 0xFF) <= 1);
CheckSafePointBit::Set(true, &glueData_.interruptVector_);
}
void ResetCheckSafePointStatus()
{
ASSERT(static_cast<uint8_t>(glueData_.interruptVector_ & 0xFF) <= 1);
CheckSafePointBit::Set(false, &glueData_.interruptVector_);
return CheckSafePointBit::Decode(glueData_.interruptVector_);
}
void SetVMNeedSuspension(bool flag)
@ -605,6 +599,11 @@ public:
return glueData_.stackLimit_;
}
void SetStackLimit(uint64_t stackLimit)
{
glueData_.stackLimit_ = stackLimit;
}
GlobalEnv *GetGlueGlobalEnv()
{
return glueData_.glueGlobalEnv_;
@ -743,7 +742,8 @@ public:
JSTaggedValue,
base::AlignedBool,
base::AlignedBool,
JSTaggedValue> {
JSTaggedValue,
base::AlignedPointer> {
enum class Index : size_t {
BCStubEntriesIndex = 0,
ExceptionIndex,
@ -770,6 +770,7 @@ public:
IsDebugModeIndex,
IsFrameDroppedIndex,
EntryFrameDroppedStateIndex,
CurrentContextIndex,
NumOfMembers
};
static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
@ -894,6 +895,11 @@ public:
return GetOffset<static_cast<size_t>(Index::EntryFrameDroppedStateIndex)>(isArch32);
}
static size_t GetCurrentContextOffset(bool isArch32)
{
return GetOffset<static_cast<size_t>(Index::CurrentContextIndex)>(isArch32);
}
alignas(EAS) BCStubEntries bcStubEntries_;
alignas(EAS) JSTaggedValue exception_ {JSTaggedValue::Hole()};
alignas(EAS) JSTaggedValue globalObject_ {JSTaggedValue::Hole()};
@ -919,6 +925,7 @@ public:
alignas(EAS) bool isDebugMode_ {false};
alignas(EAS) bool isFrameDropped_ {false};
alignas(EAS) uint64_t entryFrameDroppedState_ {FrameDroppedState::StateFalse};
alignas(EAS) EcmaContext *currentContext_ {nullptr};
};
STATIC_ASSERT_EQ_ARCH(sizeof(GlueData), GlueData::SizeArch32, GlueData::SizeArch64);
@ -927,7 +934,7 @@ public:
EcmaContext *GetCurrentEcmaContext() const
{
return currentContext_;
return glueData_.currentContext_;
}
void SwitchCurrentContext(EcmaContext *currentContext, bool isInIterate = false);
@ -940,6 +947,8 @@ public:
const GlobalEnvConstants *GetFirstGlobalConst() const;
bool IsAllContextsInitialized() const;
void ResetCheckSafePointStatus();
void SetCheckSafePointStatus();
private:
NO_COPY_SEMANTIC(JSThread);
NO_MOVE_SEMANTIC(JSThread);
@ -949,7 +958,7 @@ private:
}
void SetCurrentEcmaContext(EcmaContext *context)
{
currentContext_ = context;
glueData_.currentContext_ = context;
}
void SetArrayHClassIndexMap(const CMap<ElementsKind, ConstantIndex> &map)
@ -1004,7 +1013,6 @@ private:
CMap<ElementsKind, ConstantIndex> arrayHClassIndexMap_;
CVector<EcmaContext *> contexts_;
EcmaContext *currentContext_ {nullptr};
friend class GlobalHandleCollection;
friend class EcmaVM;
friend class EcmaContext;

View File

@ -2636,5 +2636,19 @@ JSTaggedValue RuntimeStubs::RuntimeNotifyDebuggerStatement(JSThread *thread)
}
return JSTaggedValue::Hole();
}
JSTaggedValue RuntimeStubs::RuntimeThrowStackOverflowException(JSThread *thread)
{
EcmaVM *ecmaVm = thread->GetEcmaVM();
// Multi-thread could cause stack-overflow-check failed too,
// so check thread here to distinguish it with the actual stack overflow.
ecmaVm->CheckThread();
if (LIKELY(!thread->HasPendingException())) {
ObjectFactory *factory = ecmaVm->GetFactory();
JSHandle<JSObject> error = factory->GetJSError(ErrorType::RANGE_ERROR, "Stack overflow!", false);
thread->SetException(error.GetTaggedValue());
}
return JSTaggedValue::Exception();
}
} // namespace panda::ecmascript
#endif // ECMASCRIPT_STUBS_RUNTIME_STUBS_INL_H

View File

@ -1027,11 +1027,14 @@ DEF_RUNTIME_STUBS(UpdateHotnessCounterWithProf)
return profileTypeInfo.GetRawData();
}
DEF_RUNTIME_STUBS(CheckSafePoint)
DEF_RUNTIME_STUBS(CheckSafePointAndStackOverflow)
{
auto thread = JSThread::GlueToJSThread(argGlue);
thread->CheckSafepoint();
return JSTaggedValue::Undefined().GetRawData();
if (thread->HasCheckSafePoint()) {
thread->CheckSafepoint();
return JSTaggedValue::Undefined().GetRawData();
}
return RuntimeThrowStackOverflowException(thread).GetRawData();
}
DEF_RUNTIME_STUBS(LoadICByName)
@ -1841,16 +1844,7 @@ DEF_RUNTIME_STUBS(ThrowNonConstructorException)
DEF_RUNTIME_STUBS(ThrowStackOverflowException)
{
RUNTIME_STUBS_HEADER(ThrowStackOverflowException);
EcmaVM *ecmaVm = thread->GetEcmaVM();
// Multi-thread could cause stack-overflow-check failed too,
// so check thread here to distinguish it with the actual stack overflow.
ecmaVm->CheckThread();
ObjectFactory *factory = ecmaVm->GetFactory();
JSHandle<JSObject> error = factory->GetJSError(ErrorType::RANGE_ERROR, "Stack overflow!", false);
if (LIKELY(!thread->HasPendingException())) {
thread->SetException(error.GetTaggedValue());
}
return JSTaggedValue::Exception().GetRawData();
return RuntimeThrowStackOverflowException(thread).GetRawData();
}
DEF_RUNTIME_STUBS(ThrowDerivedMustReturnException)

View File

@ -203,7 +203,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(LoadICByName) \
V(StoreICByName) \
V(UpdateHotnessCounter) \
V(CheckSafePoint) \
V(CheckSafePointAndStackOverflow) \
V(UpdateHotnessCounterWithProf) \
V(GetModuleNamespaceByIndex) \
V(GetModuleNamespaceByIndexOnJSFunc) \
@ -685,6 +685,7 @@ private:
static inline JSTaggedValue RuntimeNotifyConcurrentResult(JSThread *thread, JSTaggedValue result,
JSTaggedValue hint);
static inline JSTaggedValue RuntimeNotifyDebuggerStatement(JSThread *thread);
static inline JSTaggedValue RuntimeThrowStackOverflowException(JSThread *thread);
friend class SlowRuntimeStub;
};
} // namespace panda::ecmascript