description: update hotness counter for AOT

issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I6DDSA
Signed-off-by: K0u1hw <wangchunyang15@huawei.com>

Change-Id: I1094ac0d31cb466cbabd6159faf150a507652635
This commit is contained in:
K0u1hw 2023-02-07 11:19:54 +08:00
parent f706569cf4
commit f16ff2a015
10 changed files with 128 additions and 14 deletions

View File

@ -52,6 +52,40 @@ void BytecodeCircuitBuilder::BuildRegionInfo()
}
}
int32_t BytecodeCircuitBuilder::GetJumpOffset(uint32_t bcIndex) const
{
auto pc = GetPCByIndex(bcIndex);
auto &info = GetBytecodeInfo(bcIndex);
int32_t offset = 0;
switch (info.GetOpcode()) {
case EcmaOpcode::JEQZ_IMM8:
case EcmaOpcode::JNEZ_IMM8:
case EcmaOpcode::JMP_IMM8:
offset = static_cast<int8_t>(READ_INST_8_0());
break;
case EcmaOpcode::JNEZ_IMM16:
case EcmaOpcode::JEQZ_IMM16:
case EcmaOpcode::JMP_IMM16:
offset = static_cast<int16_t>(READ_INST_16_0());
break;
case EcmaOpcode::JMP_IMM32:
case EcmaOpcode::JNEZ_IMM32:
case EcmaOpcode::JEQZ_IMM32:
offset = static_cast<int32_t>(READ_INST_32_0());
break;
case EcmaOpcode::RETURN:
case EcmaOpcode::RETURNUNDEFINED:
case EcmaOpcode::SUSPENDGENERATOR_V8:
case EcmaOpcode::DEPRECATED_SUSPENDGENERATOR_PREF_V8_V8:
offset = -(static_cast<int32_t>(pc - GetFirstPC()));
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
break;
}
return offset;
}
void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
{
@ -797,8 +831,17 @@ void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateR
gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
inList.data(), GateType::Empty());
}
gateAcc_.NewIn(gate, 0, state);
gateAcc_.NewIn(gate, 1, depend);
if (bytecodeInfo.IsSuspend()) {
auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
GetJumpOffset(iterator.Index()),
GateType::NJSValue());
auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
gateAcc_.NewIn(gate, 0, updateHotness);
gateAcc_.NewIn(gate, 1, updateHotness);
} else {
gateAcc_.NewIn(gate, 0, state);
gateAcc_.NewIn(gate, 1, depend);
}
state = gate;
if (!bb.catchs.empty()) {
auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {gate});
@ -851,6 +894,7 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
auto &iterator = bb.GetBytecodeIterator();
const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
auto offset = GetJumpOffset(iterator.Index());
if (bytecodeInfo.IsCondJump()) {
ASSERT(!bytecodeInfo.Deopt());
auto meta = circuit_->JSBytecode(numValueInputs,
@ -861,14 +905,22 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
gateAcc_.NewIn(gate, 1, depend);
auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
if (offset < 0) {
// place update hotness Gate when offset is negative.
auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
offset,
GateType::NJSValue());
ifTrue = circuit_->NewGate(circuit_->UpdateHotness(), {ifTrue, trueRelay, offsetGate});
trueRelay = ifTrue;
}
auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
if (bb.succs.size() == 1) {
auto &bbNext = bb.succs[0];
ASSERT(bbNext->id == bb.id + 1);
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
SetBlockPred(*bbNext, ifFalse, trueRelay, isLoopBack);
SetBlockPred(*bbNext, ifTrue, falseRelay, isLoopBack);
SetBlockPred(*bbNext, ifFalse, falseRelay, isLoopBack);
SetBlockPred(*bbNext, ifTrue, trueRelay, isLoopBack);
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
} else {
@ -894,7 +946,16 @@ void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef
ASSERT(bb.succs.size() == 1);
auto &bbNext = bb.succs.at(0);
auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
SetBlockPred(*bbNext, state, depend, isLoopBack);
if (offset < 0) {
// place update hotness Gate when offset is negative.
auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
offset,
GateType::NJSValue());
auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
SetBlockPred(*bbNext, updateHotness, updateHotness, isLoopBack);
} else {
SetBlockPred(*bbNext, state, depend, isLoopBack);
}
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
}
}
@ -904,10 +965,14 @@ void BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb, GateRef &state, GateR
ASSERT(bb.succs.empty());
auto &iterator = bb.GetBytecodeIterator();
const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
GetJumpOffset(iterator.Index()),
GateType::NJSValue());
auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
// handle return.dyn bytecode
auto gate = circuit_->NewGate(circuit_->Return(),
{ state, depend, Circuit::NullGate(), circuit_->GetReturnRoot() });
{ updateHotness, updateHotness, Circuit::NullGate(), circuit_->GetReturnRoot() });
byteCodeToJSGate_[iterator.Index()] = gate;
} else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
// handle returnundefined bytecode
@ -915,7 +980,7 @@ void BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb, GateRef &state, GateR
JSTaggedValue::VALUE_UNDEFINED,
GateType::TaggedValue());
auto gate = circuit_->NewGate(circuit_->Return(),
{ state, depend, constant, circuit_->GetReturnRoot() });
{ updateHotness, updateHotness, constant, circuit_->GetReturnRoot() });
byteCodeToJSGate_[iterator.Index()] = gate;
}
}

View File

@ -277,6 +277,7 @@ public:
NO_COPY_SEMANTIC(BytecodeCircuitBuilder);
NO_MOVE_SEMANTIC(BytecodeCircuitBuilder);
void PUBLIC_API BytecodeToCircuit();
int32_t GetJumpOffset(uint32_t bcIndex) const;
void CollectRegionInfo(uint32_t bcIndex);
[[nodiscard]] Circuit* GetCircuit() const
@ -381,6 +382,11 @@ public:
return pcOffsets_[index];
}
const uint8_t *GetFirstPC() const
{
return GetPCByIndex(0);
}
const uint8_t *GetLastPC() const
{
return GetPCByIndex(GetLastBcIndex());

View File

@ -142,9 +142,11 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc)
break;
case EcmaOpcode::SUSPENDGENERATOR_V8:
flags |= BytecodeFlags::READ_THIS_OBJECT;
[[fallthrough]];
case EcmaOpcode::DEPRECATED_SUSPENDGENERATOR_PREF_V8_V8:
kind = BytecodeKind::SUSPEND;
break;
case EcmaOpcode::RESUMEGENERATOR:
kind = BytecodeKind::GENERATOR;
kind = BytecodeKind::RESUME;
break;
case EcmaOpcode::DEBUGGER:
case EcmaOpcode::NOP:
@ -176,7 +178,8 @@ BytecodeMetaData BytecodeMetaData::InitBytecodeMetaData(const uint8_t *pc)
if (kind == BytecodeKind::GENERAL ||
kind == BytecodeKind::THROW_BC ||
kind == BytecodeKind::GENERATOR) {
kind == BytecodeKind::RESUME ||
kind == BytecodeKind::SUSPEND) {
flags |= BytecodeFlags::GENERAL_BC;
}
auto size = inst.GetSize();

View File

@ -51,7 +51,8 @@ enum BytecodeKind : uint32_t {
CONDITIONAL_JUMP,
MOV,
SET_CONSTANT,
GENERATOR,
SUSPEND,
RESUME,
DISCARDED,
};
@ -117,6 +118,11 @@ public:
return GetKind() == BytecodeKind::JUMP_IMM;
}
bool IsSuspend() const
{
return GetKind() == BytecodeKind::SUSPEND;
}
bool IsSetConstant() const
{
return GetKind() == BytecodeKind::SET_CONSTANT;
@ -139,7 +145,7 @@ public:
bool IsGeneratorRelative() const
{
return GetKind() == BytecodeKind::GENERATOR;
return (GetKind() == BytecodeKind::RESUME) || (GetKind() == BytecodeKind::SUSPEND);
}
bool IsDiscarded() const
@ -481,6 +487,11 @@ public:
return metaData_.IsThrow();
}
bool IsSuspend() const
{
return metaData_.IsSuspend();
}
bool IsDiscarded() const
{
return metaData_.IsDiscarded();

View File

@ -103,6 +103,7 @@ class Variable;
V(TruncInt64ToInt1, Trunc, MachineType::I1) \
V(TruncInt64ToInt16, Trunc, MachineType::I16) \
V(TruncInt32ToInt1, Trunc, MachineType::I1) \
V(TruncInt32ToInt16, Trunc, MachineType::I16) \
V(TruncFloatToInt64, TruncFloatToInt64, MachineType::I64) \
V(ExtFloat32ToDouble, Fext, MachineType::F64) \
V(TruncDoubleToFloat32, Ftrunc, MachineType::F32) \

View File

@ -205,6 +205,7 @@ std::string MachineTypeToStr(MachineType machineType);
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, 1) \
BINARY_GATE_META_DATA_CACHE_LIST(V) \
UNARY_GATE_META_DATA_CACHE_LIST(V)

View File

@ -53,6 +53,8 @@ void SlowPathLowering::CallRuntimeLowering()
LowerDeoptCheck(gate);
} else if (op == OpCode::CONSTRUCT) {
LowerConstruct(gate);
} else if (op == OpCode::UPDATE_HOTNESS) {
LowerUpdateHotness(gate);
}
}
@ -3674,4 +3676,28 @@ void SlowPathLowering::LowerConstruct(GateRef gate)
GateRef constructGate = builder_.Call(cs, glue_, target, depend, args);
ReplaceHirToJSCall(gate, constructGate);
}
void SlowPathLowering::LowerUpdateHotness(GateRef gate)
{
Environment env(gate, circuit_, &builder_);
GateRef jsFunc = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
GateRef method = builder_.Load(VariableType::JS_ANY(), jsFunc, builder_.IntPtr(JSFunctionBase::METHOD_OFFSET));
GateRef hotness = builder_.Load(VariableType::INT16(), method, builder_.IntPtr(Method::LITERAL_INFO_OFFSET));
GateRef value = builder_.ZExtInt16ToInt32(hotness);
GateRef offset = acc_.GetValueIn(gate, 0);
GateRef newValue = builder_.Int32Add(value, offset);
DEFVAlUE(newHotness, (&builder_), VariableType::INT16(), builder_.TruncInt32ToInt16(newValue));
Label slowPath(&builder_);
Label dispatch(&builder_);
builder_.Branch(builder_.Int32LessThan(newValue, builder_.Int32(0)), &slowPath, &dispatch);
builder_.Bind(&slowPath);
{
builder_.CallRuntime(glue_, RTSTUB_ID(UpdateHotnessCounter), Circuit::NullGate(), { jsFunc });
newHotness = builder_.Int16(EcmaInterpreter::METHOD_HOTNESS_THRESHOLD);
builder_.Jump(&dispatch);
}
builder_.Bind(&dispatch);
builder_.Store(VariableType::VOID(), glue_, method, builder_.IntPtr(Method::LITERAL_INFO_OFFSET), *newHotness);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate());
}
} // namespace panda::ecmascript

View File

@ -303,6 +303,7 @@ private:
void LowerConstPoolData(GateRef gate);
void LowerDeoptCheck(GateRef gate);
void LowerConstruct(GateRef gate);
void LowerUpdateHotness(GateRef gate);
TSManager *tsManager_ {nullptr};
const MethodLiteral *methodLiteral_ {nullptr};

View File

@ -11,4 +11,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
9000003000000.25
90300.25

View File

@ -22,4 +22,4 @@ function foo(n: number) {
return x;
}
print(foo(3000000));
print(foo(300));