Reason:add aot call stack overflow check

Description:add aot call stack overflow check
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7PMSM?from=project-issue

Signed-off-by: wupengyong <wupengyong@huawei.com>
Change-Id: I1a31c928fc406364aa81cc2a5a5037d920f1ed04
This commit is contained in:
wupengyong 2023-08-07 16:24:38 +08:00
parent 6d049d6448
commit b389b49691
13 changed files with 164 additions and 65 deletions

View File

@ -1055,8 +1055,8 @@ void BytecodeCircuitBuilder::BuildSubCircuit()
ASSERT(stateCur != Circuit::NullGate());
ASSERT(dependCur != Circuit::NullGate());
if (IsEntryBlock(bb.id)) {
if (NeedUpdateHotness()) {
stateCur = circuit_->NewGate(circuit_->UpdateHotness(), {stateCur, dependCur});
if (NeedCheckSafePointAndStackOver()) {
stateCur = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {stateCur, dependCur});
dependCur = stateCur;
}
auto &bbNext = graph_[bb.id + 1];

View File

@ -317,7 +317,7 @@ public:
return jsGatesToByteCode_.at(gate);
}
bool NeedUpdateHotness() const
bool NeedCheckSafePointAndStackOver() const
{
return !isInline_ && !method_->IsNoGC();
}

View File

@ -127,6 +127,11 @@ GateRef CircuitBuilder::DependRelay(GateRef state, GateRef depend)
return circuit_->NewGate(circuit_->DependRelay(), { state, depend });
}
GateRef CircuitBuilder::ReadSp()
{
return circuit_->NewGate(circuit_->ReadSp(), MachineType::I64, GateType::NJSValue());
}
GateRef CircuitBuilder::Arguments(size_t index)
{
auto argListOfCircuit = circuit_->GetArgRoot();

View File

@ -352,6 +352,7 @@ public:
GateRef SwitchCase(GateRef switchBranch, int64_t value);
GateRef DefaultCase(GateRef switchBranch);
GateRef DependRelay(GateRef state, GateRef depend);
GateRef ReadSp();
GateRef BinaryArithmetic(const GateMetaData* meta, MachineType machineType,
GateRef left, GateRef right, GateType gateType = GateType::Empty());
GateRef BinaryCmp(const GateMetaData* meta, GateRef left, GateRef right);

View File

@ -230,58 +230,59 @@ std::string MachineTypeToStr(MachineType machineType);
V(UnsignedFloatToInt, UNSIGNED_FLOAT_TO_INT, GateFlags::NONE_FLAG, 0, 0, 1) \
V(Bitcast, BITCAST, GateFlags::NONE_FLAG, 0, 0, 1)
#define IMMUTABLE_META_DATA_CACHE_LIST(V) \
V(CircuitRoot, CIRCUIT_ROOT, GateFlags::NONE_FLAG, 0, 0, 0) \
V(StateEntry, STATE_ENTRY, GateFlags::ROOT, 0, 0, 0) \
V(DependEntry, DEPEND_ENTRY, GateFlags::ROOT, 0, 0, 0) \
V(ReturnList, RETURN_LIST, GateFlags::ROOT, 0, 0, 0) \
V(ArgList, ARG_LIST, GateFlags::ROOT, 0, 0, 0) \
V(Return, RETURN, GateFlags::HAS_ROOT, 1, 1, 1) \
V(ReturnVoid, RETURN_VOID, GateFlags::HAS_ROOT, 1, 1, 0) \
V(Throw, THROW, GateFlags::CONTROL, 1, 1, 1) \
V(OrdinaryBlock, ORDINARY_BLOCK, GateFlags::CONTROL, 1, 0, 0) \
V(IfBranch, IF_BRANCH, GateFlags::CONTROL, 1, 0, 1) \
V(IfTrue, IF_TRUE, GateFlags::CONTROL, 1, 0, 0) \
V(IfFalse, IF_FALSE, GateFlags::CONTROL, 1, 0, 0) \
V(LoopBegin, LOOP_BEGIN, GateFlags::CONTROL, 2, 0, 0) \
V(LoopBack, LOOP_BACK, GateFlags::CONTROL, 1, 0, 0) \
V(LoopExit, LOOP_EXIT, GateFlags::CONTROL, 1, 0, 0) \
V(LoopExitDepend, LOOP_EXIT_DEPEND, GateFlags::FIXED, 1, 1, 0) \
V(LoopExitValue, LOOP_EXIT_VALUE, GateFlags::FIXED, 1, 0, 1) \
V(DependRelay, DEPEND_RELAY, GateFlags::FIXED, 1, 1, 0) \
V(IfSuccess, IF_SUCCESS, GateFlags::CONTROL, 1, 0, 0) \
V(IfException, IF_EXCEPTION, GateFlags::CONTROL, 1, 1, 0) \
V(GetException, GET_EXCEPTION, GateFlags::NONE_FLAG, 1, 1, 0) \
V(GetConstPool, GET_CONSTPOOL, GateFlags::NO_WRITE, 0, 1, 1) \
V(GetGlobalEnv, GET_GLOBAL_ENV, GateFlags::NO_WRITE, 0, 1, 0) \
V(StateSplit, STATE_SPLIT, GateFlags::CHECKABLE, 1, 1, 0) \
V(Load, LOAD, GateFlags::NO_WRITE, 0, 1, 1) \
V(Store, STORE, GateFlags::NONE_FLAG, 0, 1, 2) \
V(TypedCallCheck, TYPED_CALL_CHECK, GateFlags::CHECKABLE, 1, 1, 3) \
V(HeapObjectCheck, HEAP_OBJECT_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(COWArrayCheck, COW_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(ArrayGuardianCheck, ARRAY_GUARDIAN_CHECK, GateFlags::CHECKABLE, 1, 1, 0) \
V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(DeoptCheck, DEOPT_CHECK, GateFlags::NO_WRITE, 1, 1, 3) \
V(StoreProperty, STORE_PROPERTY, GateFlags::NONE_FLAG, 1, 1, 3) \
V(StorePropertyNoBarrier, STORE_PROPERTY_NO_BARRIER, GateFlags::NONE_FLAG, 1, 1, 3) \
V(ToLength, TO_LENGTH, GateFlags::NONE_FLAG, 1, 1, 1) \
V(DefaultCase, DEFAULT_CASE, GateFlags::CONTROL, 1, 0, 0) \
V(LoadArrayLength, LOAD_ARRAY_LENGTH, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedNewAllocateThis, TYPED_NEW_ALLOCATE_THIS, GateFlags::CHECKABLE, 1, 1, 2) \
V(TypedSuperAllocateThis, TYPED_SUPER_ALLOCATE_THIS, GateFlags::CHECKABLE, 1, 1, 2) \
V(GetSuperConstructor, GET_SUPER_CONSTRUCTOR, GateFlags::NO_WRITE, 1, 1, 1) \
V(UpdateHotness, UPDATE_HOTNESS, GateFlags::NO_WRITE, 1, 1, 0) \
V(Dead, DEAD, GateFlags::NONE_FLAG, 0, 0, 0) \
V(FrameArgs, FRAME_ARGS, GateFlags::NONE_FLAG, 0, 0, 4) \
V(GetEnv, GET_ENV, GateFlags::NONE_FLAG, 0, 0, 1) \
V(ConvertHoleAsUndefined, CONVERT_HOLE_AS_UNDEFINED, GateFlags::NO_WRITE, 1, 1, 1) \
V(StartAllocate, START_ALLOCATE, GateFlags::NONE_FLAG, 0, 1, 0) \
V(FinishAllocate, FINISH_ALLOCATE, GateFlags::NONE_FLAG, 0, 1, 0) \
V(LoadGetter, LOAD_GETTER, GateFlags::NONE_FLAG, 0, 1, 2) \
V(LoadSetter, LOAD_SETTER, GateFlags::NONE_FLAG, 0, 1, 2) \
BINARY_GATE_META_DATA_CACHE_LIST(V) \
#define IMMUTABLE_META_DATA_CACHE_LIST(V) \
V(CircuitRoot, CIRCUIT_ROOT, GateFlags::NONE_FLAG, 0, 0, 0) \
V(StateEntry, STATE_ENTRY, GateFlags::ROOT, 0, 0, 0) \
V(DependEntry, DEPEND_ENTRY, GateFlags::ROOT, 0, 0, 0) \
V(ReturnList, RETURN_LIST, GateFlags::ROOT, 0, 0, 0) \
V(ArgList, ARG_LIST, GateFlags::ROOT, 0, 0, 0) \
V(Return, RETURN, GateFlags::HAS_ROOT, 1, 1, 1) \
V(ReturnVoid, RETURN_VOID, GateFlags::HAS_ROOT, 1, 1, 0) \
V(Throw, THROW, GateFlags::CONTROL, 1, 1, 1) \
V(OrdinaryBlock, ORDINARY_BLOCK, GateFlags::CONTROL, 1, 0, 0) \
V(IfBranch, IF_BRANCH, GateFlags::CONTROL, 1, 0, 1) \
V(IfTrue, IF_TRUE, GateFlags::CONTROL, 1, 0, 0) \
V(IfFalse, IF_FALSE, GateFlags::CONTROL, 1, 0, 0) \
V(LoopBegin, LOOP_BEGIN, GateFlags::CONTROL, 2, 0, 0) \
V(LoopBack, LOOP_BACK, GateFlags::CONTROL, 1, 0, 0) \
V(LoopExit, LOOP_EXIT, GateFlags::CONTROL, 1, 0, 0) \
V(LoopExitDepend, LOOP_EXIT_DEPEND, GateFlags::FIXED, 1, 1, 0) \
V(LoopExitValue, LOOP_EXIT_VALUE, GateFlags::FIXED, 1, 0, 1) \
V(DependRelay, DEPEND_RELAY, GateFlags::FIXED, 1, 1, 0) \
V(IfSuccess, IF_SUCCESS, GateFlags::CONTROL, 1, 0, 0) \
V(IfException, IF_EXCEPTION, GateFlags::CONTROL, 1, 1, 0) \
V(GetException, GET_EXCEPTION, GateFlags::NONE_FLAG, 1, 1, 0) \
V(GetConstPool, GET_CONSTPOOL, GateFlags::NO_WRITE, 0, 1, 1) \
V(GetGlobalEnv, GET_GLOBAL_ENV, GateFlags::NO_WRITE, 0, 1, 0) \
V(StateSplit, STATE_SPLIT, GateFlags::CHECKABLE, 1, 1, 0) \
V(Load, LOAD, GateFlags::NO_WRITE, 0, 1, 1) \
V(Store, STORE, GateFlags::NONE_FLAG, 0, 1, 2) \
V(TypedCallCheck, TYPED_CALL_CHECK, GateFlags::CHECKABLE, 1, 1, 3) \
V(HeapObjectCheck, HEAP_OBJECT_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(StableArrayCheck, STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(COWArrayCheck, COW_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(ArrayGuardianCheck, ARRAY_GUARDIAN_CHECK, GateFlags::CHECKABLE, 1, 1, 0) \
V(HClassStableArrayCheck, HCLASS_STABLE_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \
V(DeoptCheck, DEOPT_CHECK, GateFlags::NO_WRITE, 1, 1, 3) \
V(StoreProperty, STORE_PROPERTY, GateFlags::NONE_FLAG, 1, 1, 3) \
V(StorePropertyNoBarrier, STORE_PROPERTY_NO_BARRIER, GateFlags::NONE_FLAG, 1, 1, 3) \
V(ToLength, TO_LENGTH, GateFlags::NONE_FLAG, 1, 1, 1) \
V(DefaultCase, DEFAULT_CASE, GateFlags::CONTROL, 1, 0, 0) \
V(LoadArrayLength, LOAD_ARRAY_LENGTH, GateFlags::NO_WRITE, 1, 1, 1) \
V(TypedNewAllocateThis, TYPED_NEW_ALLOCATE_THIS, GateFlags::CHECKABLE, 1, 1, 2) \
V(TypedSuperAllocateThis, TYPED_SUPER_ALLOCATE_THIS, GateFlags::CHECKABLE, 1, 1, 2) \
V(GetSuperConstructor, GET_SUPER_CONSTRUCTOR, GateFlags::NO_WRITE, 1, 1, 1) \
V(CheckSafePointAndStackOver, CHECK_SAFEPOINT_AND_STACKOVER, GateFlags::NO_WRITE, 1, 1, 0) \
V(Dead, DEAD, GateFlags::NONE_FLAG, 0, 0, 0) \
V(FrameArgs, FRAME_ARGS, GateFlags::NONE_FLAG, 0, 0, 4) \
V(GetEnv, GET_ENV, GateFlags::NONE_FLAG, 0, 0, 1) \
V(ConvertHoleAsUndefined, CONVERT_HOLE_AS_UNDEFINED, GateFlags::NO_WRITE, 1, 1, 1) \
V(StartAllocate, START_ALLOCATE, GateFlags::NONE_FLAG, 0, 1, 0) \
V(FinishAllocate, FINISH_ALLOCATE, GateFlags::NONE_FLAG, 0, 1, 0) \
V(LoadGetter, LOAD_GETTER, GateFlags::NONE_FLAG, 0, 1, 2) \
V(LoadSetter, LOAD_SETTER, GateFlags::NONE_FLAG, 0, 1, 2) \
V(ReadSp, READSP, GateFlags::NONE_FLAG, 0, 0, 0) \
BINARY_GATE_META_DATA_CACHE_LIST(V) \
UNARY_GATE_META_DATA_CACHE_LIST(V)
#define GATE_META_DATA_LIST_WITH_VALUE_IN(V) \

View File

@ -202,6 +202,7 @@ void LLVMIRBuilder::InitializeHandlers()
{OpCode::MUL_WITH_OVERFLOW, &LLVMIRBuilder::HandleMulWithOverflow},
{OpCode::EXTRACT_VALUE, &LLVMIRBuilder::HandleExtractValue},
{OpCode::SQRT, &LLVMIRBuilder::HandleSqrt},
{OpCode::READSP, &LLVMIRBuilder::HandleReadSp},
};
illegalOpHandlers_ = {
OpCode::NOP, OpCode::CIRCUIT_ROOT, OpCode::DEPEND_ENTRY,
@ -476,6 +477,12 @@ LLVMTypeRef LLVMIRBuilder::GetMachineRepType(MachineRep rep) const
return dstType;
}
void LLVMIRBuilder::HandleReadSp(GateRef gate)
{
ASSERT(acc_.GetOpCode(gate) == OpCode::READSP);
VisitReadSp(gate);
}
void LLVMIRBuilder::HandleCall(GateRef gate)
{
std::vector<GateRef> ins;
@ -792,6 +799,12 @@ LLVMValueRef LLVMIRBuilder::GetCallee(const std::vector<GateRef> &inList, const
return callee;
}
void LLVMIRBuilder::VisitReadSp(GateRef gate)
{
LLVMValueRef spValue = GetCurrentSP();
gate2LValue_[gate] = spValue;
}
void LLVMIRBuilder::VisitCall(GateRef gate, const std::vector<GateRef> &inList, OpCode op)
{
size_t targetIndex = static_cast<size_t>(CallInputs::TARGET);

View File

@ -356,7 +356,8 @@ private:
V(SubWithOverflow, (GateRef gate, GateRef e1, GateRef e2)) \
V(MulWithOverflow, (GateRef gate, GateRef e1, GateRef e2)) \
V(ExtractValue, (GateRef gate, GateRef e1, GateRef e2)) \
V(Sqrt, (GateRef gate, GateRef e1))
V(Sqrt, (GateRef gate, GateRef e1)) \
V(ReadSp, (GateRef gate))
// runtime/common stub ID, opcodeOffset for bc stub
using StubIdType = std::variant<RuntimeStubCSigns::ID, CommonStubCSigns::ID, LLVMValueRef>;

View File

@ -63,8 +63,8 @@ void SlowPathLowering::CallRuntimeLowering()
case OpCode::TYPEDFASTCALL:
LowerTypedFastCall(gate);
break;
case OpCode::UPDATE_HOTNESS:
LowerUpdateHotness(gate);
case OpCode::CHECK_SAFEPOINT_AND_STACKOVER:
LowerCheckSafePointAndStackOver(gate);
break;
case OpCode::GET_ENV:
LowerGetEnv(gate);
@ -3139,19 +3139,33 @@ void SlowPathLowering::LowerTypedFastCall(GateRef gate)
ReplaceHirWithPendingException(gate, state, result, result);
}
void SlowPathLowering::LowerUpdateHotness(GateRef gate)
void SlowPathLowering::LowerCheckSafePointAndStackOver(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef interruptsFlag = builder_.Load(VariableType::INT8(), glue_,
builder_.IntPtr(JSThread::GlueData::GetInterruptVectorOffset(builder_.GetCompilationConfig()->Is32Bit())));
Label slowPath(&builder_);
Label dispatch(&builder_);
Label checkStackOver(&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 spValue = builder_.ReadSp();
builder_.Branch(builder_.Int8Equal(interruptsFlag,
builder_.Int8(VmThreadControl::VM_NEED_SUSPENSION)), &slowPath, &dispatch);
builder_.Int8(VmThreadControl::VM_NEED_SUSPENSION)), &slowPath, &checkStackOver);
builder_.Bind(&slowPath);
{
LowerCallRuntime(glue_, RTSTUB_ID(CheckSafePoint), { }, true);
builder_.Jump(&dispatch);
LowerCallRuntime(glue_, RTSTUB_ID(CheckSafePoint), {}, true);
builder_.Jump(&checkStackOver);
}
builder_.Bind(&checkStackOver);
{
builder_.Branch(builder_.Int64LessThanOrEqual(spValue, stackLimit), &stackOverflow, &dispatch);
builder_.Bind(&stackOverflow);
{
GateRef res = LowerCallRuntime(glue_, RTSTUB_ID(ThrowStackOverflowException), {}, true);
builder_.Return(res);
}
}
builder_.Bind(&dispatch);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());

View File

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

View File

@ -90,6 +90,7 @@ group("ark_aot_ts_test") {
"exception_case10",
"exception_case11",
"exception_case12",
"exception_case13",
"exception_case2",
"exception_case3",
"exception_case4",

View File

@ -0,0 +1,19 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("exception_case13") {
deps = []
is_enable_trace_deopt = true
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare function print(str:any):string;
function f():any {
print("stack overflow");
}
function t() {
try {
t();
} catch (e) {
f();
}
}
try{
t();
} catch(e){}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
stack overflow