!8479 Fix ASSERTION FAILED: newHclass->IsPrototype()

Merge pull request !8479 from Efremov Andrey/aot-hclass-transition
This commit is contained in:
openharmony_ci 2024-08-09 02:50:52 +00:00 committed by Gitee
commit 47e7002658
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
16 changed files with 254 additions and 122 deletions

View File

@ -94,6 +94,18 @@ bool Circuit::AddComment(GateRef g, std::string &&str)
return true;
}
std::string_view Circuit::GetComment(GateRef gate)
{
if (debugInfo_ == nullptr || !debugInfo_->IsEnable()) {
return "";
}
size_t index;
if (!GetDebugInfo(gate, index)) {
return "";
}
return debugInfo_->GetComment(index);
}
bool Circuit::GetDebugInfo(GateRef g, size_t &index) const
{
auto it = gateToDInfo_.find(g);

View File

@ -241,6 +241,7 @@ private:
public:
void Print(GateRef gate) const;
bool AddComment(GateRef g, std::string &&str);
std::string_view GetComment(GateRef gate);
private:
GateType GetGateType(GateRef gate) const;

View File

@ -84,4 +84,11 @@ const std::string &DebugInfo::GetComment(const std::string &funcName, size_t ind
}
return FuncDebugInfo::EmptyComment();
}
const std::string &DebugInfo::GetComment(size_t index) const
{
ASSERT(!dInfos_.empty());
auto *info = dInfos_.back();
return info->GetComment(index);
}
} // namespace panda::ecmascript::kungfu

View File

@ -31,6 +31,7 @@ public:
size_t AddComment(std::string &&str);
void AddFuncDebugInfo(const std::string &name);
const std::string &GetComment(const std::string &funcName, size_t index) const;
const std::string &GetComment(size_t index) const;
private:
class FuncDebugInfo {

View File

@ -246,8 +246,9 @@ std::string Gate::GetValueInAndOut(bool inListPreview, size_t highlightIdx) cons
{
auto opcode = GetOpCode();
if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
std::string log("{\"id\":" + std::to_string(id_) + ", \"op\":\"" + GateMetaData::Str(opcode) + "\", ");
log += "\",\"in\":[";
std::ostringstream log("{\"id\":");
log << std::to_string(id_) << ", \"op\":\"" << GateMetaData::Str(opcode) << "\", ";
log << "\",\"in\":[";
size_t idx = 0;
auto stateSize = GetStateCount();
auto dependSize = GetDependCount();
@ -270,23 +271,23 @@ std::string Gate::GetValueInAndOut(bool inListPreview, size_t highlightIdx) cons
start += frameStateSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
log += "], \"out\":[";
log << "], \"out\":[";
if (!IsFirstOutNull()) {
const Out *curOut = GetFirstOutConst();
opcode = curOut->GetGateConst()->GetOpCode();
log += std::to_string(curOut->GetGateConst()->GetId()) +
log << std::to_string(curOut->GetGateConst()->GetId()) +
(inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
while (!curOut->IsNextOutNull()) {
curOut = curOut->GetNextOutConst();
log += ", " + std::to_string(curOut->GetGateConst()->GetId()) +
log << ", " << std::to_string(curOut->GetGateConst()->GetId()) <<
(inListPreview ? std::string(":" + GateMetaData::Str(opcode))
: std::string(""));
}
}
log += "]},";
return log;
log << "]},";
return log.str();
}
return "";
}
@ -787,12 +788,90 @@ std::string Gate::GateTypeStr(GateType gateType) const
return name + std::string("-gateType(") + std::to_string(r) + std::string(")");
}
void Gate::Print(std::string additionOp, bool inListPreview, size_t highlightIdx) const
void Gate::Print(std::string additionOp, bool inListPreview, size_t highlightIdx, std::string_view comment) const
{
LOG_COMPILER(INFO) << ToString(additionOp, inListPreview, highlightIdx);
LOG_COMPILER(INFO) << ToString(additionOp, inListPreview, highlightIdx, comment);
}
std::string Gate::ToString(std::string additionOp, bool inListPreview, size_t highlightIdx) const
void Gate::DumpHeader(std::ostringstream &oss, const std::string& additionOp) const
{
auto opcode = GetOpCode();
ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
oss << "{\"id\":" << std::to_string(id_) << ", \"op\":\"" << GateMetaData::Str(opcode) << "\", ";
if (additionOp.compare("") != 0) {
auto additionOpName = (opcode == OpCode::JS_BYTECODE) ? "bytecode" : "typedop";
oss << "\"" << additionOpName << "\":\"" << additionOp;
oss << "\", ";
}
oss << "\"MType\":\"" << MachineTypeStr(GetMachineType()) << ", ";
oss << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", ";
oss << "type=" << GateTypeStr(type_) << ", ";
oss << "stamp=" << std::to_string(static_cast<uint32_t>(stamp_)) << ", ";
oss << "mark=" << std::to_string(static_cast<uint32_t>(mark_)) << ", ";
}
void Gate::DumpInputs(std::ostringstream &oss, bool inListPreview, size_t highlightIdx) const
{
[[maybe_unused]] auto opcode = GetOpCode();
ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
size_t idx = 0;
auto stateSize = GetStateCount();
auto dependSize = GetDependCount();
auto valueSize = GetInValueCount();
auto frameStateSize = GetInFrameStateCount();
auto rootSize = GetRootCount();
size_t start = 0;
size_t end = stateSize;
oss << "\",\"in\":[";
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
end += dependSize;
start += stateSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
end += valueSize;
start += dependSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
end += frameStateSize;
start += valueSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss);
end += rootSize;
start += frameStateSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, oss, true);
oss << "]";
}
void Gate::DumpOutputs(std::ostringstream &oss, bool inListPreview) const
{
auto opcode = GetOpCode();
ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
oss << ", \"out\":[";
if (!IsFirstOutNull()) {
const Out *curOut = GetFirstOutConst();
opcode = curOut->GetGateConst()->GetOpCode();
oss << std::to_string(curOut->GetGateConst()->GetId()) +
(inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
while (!curOut->IsNextOutNull()) {
curOut = curOut->GetNextOutConst();
oss << ", " + std::to_string(curOut->GetGateConst()->GetId()) +
(inListPreview ? std::string(":" + GateMetaData::Str(opcode))
: std::string(""));
}
}
oss << "]";
}
static void DumpComment(std::ostringstream &oss, std::string_view comment)
{
oss << ", \"comment\":\"" << comment << "\"";
}
std::string Gate::ToString(std::string additionOp, bool inListPreview, size_t highlightIdx,
std::string_view comment) const
{
auto opcode = GetOpCode();
if (opcode == OpCode::NOP || opcode == OpCode::DEAD) {
@ -800,7 +879,14 @@ std::string Gate::ToString(std::string additionOp, bool inListPreview, size_t hi
}
std::ostringstream oss;
oss << std::dec << DumpHeader(additionOp) << DumpInputs(inListPreview, highlightIdx) << DumpOutputs(inListPreview);
oss << std::dec;
DumpHeader(oss, additionOp);
DumpInputs(oss, inListPreview, highlightIdx);
DumpOutputs(oss, inListPreview);
if (!comment.empty()) {
DumpComment(oss, comment);
}
oss << "},";
return oss.str();
}
@ -808,15 +894,14 @@ void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlight
{
auto opcode = GetOpCode();
if (opcode != OpCode::NOP && opcode != OpCode::DEAD) {
std::string log("(\"id\"=" + std::to_string(id_) + ", \"op\"=\"" + GateMetaData::Str(opcode) + "\", ");
log += ((bytecode.compare("") == 0) ? "" : "bytecode=") + bytecode;
log += ((bytecode.compare("") == 0) ? "" : ", ");
log += "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", ";
std::ostringstream oss;
oss << std::hex << TryGetValue();
log += "bitfield=0x" + oss.str() + ", ";
log += "type=" + GateTypeStr(type_) + ", ";
log += "\", in=[";
std::ostringstream log;
log << "(\"id\"=" << std::to_string(id_) << ", \"op\"=\"" << GateMetaData::Str(opcode) << "\", ";
log << ((bytecode.compare("") == 0) ? "" : "bytecode=") << bytecode;
log << ((bytecode.compare("") == 0) ? "" : ", ");
log << "\"MType\"=\"" + MachineTypeStr(GetMachineType()) + ", ";
log << "bitfield=0x" << std::hex << TryGetValue() << std::dec << ", ";
log << "type=" + GateTypeStr(type_) + ", ";
log << "\", in=[";
size_t idx = 0;
auto stateSize = GetStateCount();
@ -840,42 +925,42 @@ void Gate::ShortPrint(std::string bytecode, bool inListPreview, size_t highlight
start += frameStateSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
log += "], out=[";
log << "], out=[";
if (!IsFirstOutNull()) {
const Out *curOut = GetFirstOutConst();
opcode = curOut->GetGateConst()->GetOpCode();
log += std::to_string(curOut->GetGateConst()->GetId()) +
log << std::to_string(curOut->GetGateConst()->GetId()) <<
(inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
while (!curOut->IsNextOutNull()) {
curOut = curOut->GetNextOutConst();
log += ", " + std::to_string(curOut->GetGateConst()->GetId()) +
log << ", " << std::to_string(curOut->GetGateConst()->GetId()) <<
(inListPreview ? std::string(":" + GateMetaData::Str(opcode))
: std::string(""));
}
}
log += "])";
LOG_COMPILER(INFO) << std::dec << log;
log << "])";
LOG_COMPILER(INFO) << std::dec << log.str();
}
}
size_t Gate::PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
std::string &log, bool isEnd) const
std::ostringstream &log, bool isEnd) const
{
log += "[";
log << "[";
for (; idx < numIns; idx++) {
log += ((idx == size) ? "" : ", ");
log += ((idx == highlightIdx) ? "\033[4;31m" : "");
log += ((IsInGateNull(idx)
log << ((idx == size) ? "" : ", ");
log << ((idx == highlightIdx) ? "\033[4;31m" : "");
log << ((IsInGateNull(idx)
? "N"
: (std::to_string(GetInGateConst(idx)->GetId()) +
(inListPreview ? std::string(":" + GateMetaData::Str(GetInGateConst(idx)->GetOpCode()))
: std::string("")))));
log += ((idx == highlightIdx) ? "\033[0m" : "");
log << ((idx == highlightIdx) ? "\033[0m" : "");
}
log += "]";
log += ((isEnd) ? "" : ", ");
log << "]";
log << ((isEnd) ? "" : ", ");
return idx;
}

View File

@ -179,12 +179,13 @@ public:
[[nodiscard]] size_t GetInValueStarts() const;
[[nodiscard]] size_t GetRootCount() const;
[[nodiscard]] size_t GetInFrameStateStarts() const;
void AppendIn(const Gate *in); // considered very slow
void Print(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1) const;
std::string ToString(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1) const;
void Print(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1,
std::string_view comment = "") const;
std::string ToString(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1,
std::string_view comment = "") const;
void ShortPrint(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1) const;
size_t PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
std::string &log, bool isEnd = false) const;
std::ostringstream &log, bool isEnd = false) const;
void PrintGateWithAdditionOp(std::string additionOp) const;
void PrintWithBytecode() const;
void CheckNullInput() const;
@ -278,77 +279,11 @@ private:
}
return 0;
}
std::string DumpHeader(const std::string& additionOp) const
{
auto opcode = GetOpCode();
ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
void DumpHeader(std::ostringstream &oss, const std::string& additionOp) const;
std::string log("{\"id\":" + std::to_string(id_) + ", \"op\":\"" + GateMetaData::Str(opcode) + "\", ");
std::string additionOpName = (opcode == OpCode::JS_BYTECODE) ? "bytecode" : "typedop";
log += ((additionOp.compare("") == 0) ? "" : "\"" + additionOpName + "\":\"") + additionOp;
log += ((additionOp.compare("") == 0) ? "" : "\", ");
log += "\"MType\":\"" + MachineTypeStr(GetMachineType()) + ", ";
void DumpInputs(std::ostringstream &oss, bool inListPreview, size_t highlightIdx) const;
std::ostringstream oss;
oss << std::hex << TryGetValue();
log += "bitfield=0x" + oss.str() + ", ";
log += "type=" + GateTypeStr(type_) + ", ";
log += "stamp=" + std::to_string(static_cast<uint32_t>(stamp_)) + ", ";
log += "mark=" + std::to_string(static_cast<uint32_t>(mark_)) + ", ";
return log;
}
std::string DumpInputs(bool inListPreview, size_t highlightIdx) const
{
[[maybe_unused]] auto opcode = GetOpCode();
ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
size_t idx = 0;
auto stateSize = GetStateCount();
auto dependSize = GetDependCount();
auto valueSize = GetInValueCount();
auto frameStateSize = GetInFrameStateCount();
auto rootSize = GetRootCount();
size_t start = 0;
size_t end = stateSize;
std::string log("\",\"in\":[");
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
end += dependSize;
start += stateSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
end += valueSize;
start += dependSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
end += frameStateSize;
start += valueSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log);
end += rootSize;
start += frameStateSize;
idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true);
return log;
}
std::string DumpOutputs(bool inListPreview) const
{
auto opcode = GetOpCode();
ASSERT(opcode != OpCode::NOP && opcode != OpCode::DEAD);
std::string log("], \"out\":[");
if (!IsFirstOutNull()) {
const Out *curOut = GetFirstOutConst();
opcode = curOut->GetGateConst()->GetOpCode();
log += std::to_string(curOut->GetGateConst()->GetId()) +
(inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string(""));
while (!curOut->IsNextOutNull()) {
curOut = curOut->GetNextOutConst();
log += ", " + std::to_string(curOut->GetGateConst()->GetId()) +
(inListPreview ? std::string(":" + GateMetaData::Str(opcode))
: std::string(""));
}
}
log += "]},";
return log;
}
void DumpOutputs(std::ostringstream &oss, bool inListPreview) const;
// ...
// out(2)

View File

@ -757,7 +757,8 @@ EcmaOpcode GateAccessor::GetByteCodeOpcode(GateRef gate) const
void GateAccessor::Print(GateRef gate) const
{
Gate *gatePtr = circuit_->LoadGatePtr(gate);
gatePtr->Print();
auto comment = circuit_->GetComment(gate);
gatePtr->Print("", false, -1, comment);
}
std::string GateAccessor::ToString(GateRef gate) const

View File

@ -185,11 +185,11 @@ bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &sel
JSTaggedValue protoOrHClass = func->GetProtoOrHClass();
if (protoOrHClass.IsJSHClass()) {
// need transition
JSHandle<JSTaggedValue> hclass(thread, protoOrHClass);
JSHandle<JSTaggedValue> newClass = JSHClass::SetPrototypeWithNotification(thread, hclass, value);
JSHandle<JSHClass> hclass(thread, JSHClass::Cast(protoOrHClass.GetTaggedObject()));
JSHandle<JSHClass> newClass = JSHClass::SetPrototypeWithNotification(thread, hclass, value);
func->SetProtoOrHClass(thread, newClass);
// Forbide to profile for changing the function prototype after an instance of the function has been created
if (!JSHClass::Cast(hclass->GetTaggedObject())->IsTS() && thread->GetEcmaVM()->IsEnablePGOProfiler()) {
if (!hclass->IsTS() && thread->GetEcmaVM()->IsEnablePGOProfiler()) {
EntityId ctorMethodId = Method::Cast(func->GetMethod().GetTaggedObject())->GetMethodId();
thread->GetEcmaVM()->GetPGOProfiler()->InsertSkipCtorMethodIdSafe(ctorMethodId);
}

View File

@ -479,21 +479,26 @@ void JSHClass::SetPrototype(const JSThread *thread, JSTaggedValue proto)
SetPrototype(thread, protoHandle);
}
JSHandle<JSTaggedValue> JSHClass::SetPrototypeWithNotification(const JSThread *thread,
const JSHandle<JSTaggedValue> &hclass,
const JSHandle<JSTaggedValue> &proto)
JSHandle<JSHClass> JSHClass::SetPrototypeWithNotification(const JSThread *thread,
const JSHandle<JSHClass> &hclass,
const JSHandle<JSTaggedValue> &proto)
{
JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, JSHandle<JSHClass>::Cast(hclass), proto);
JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>::Cast(hclass), newClass);
return JSHandle<JSTaggedValue>(newClass);
// `hclass` can become prototype inside `TransitionProto` if `hclass` is HClass of `proto`.
// In this case we don't need to notify
auto wasPrototype = hclass->IsPrototype();
JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, hclass, proto);
if (wasPrototype) {
ASSERT(hclass->IsPrototype());
JSHClass::NotifyHclassChanged(thread, hclass, newClass);
}
return newClass;
}
void JSHClass::SetPrototypeTransition(JSThread *thread, const JSHandle<JSObject> &object,
const JSHandle<JSTaggedValue> &proto)
{
JSHandle<JSHClass> hclass(thread, object->GetJSHClass());
JSHandle<JSHClass> newClass = JSHClass::TransitionProto(thread, hclass, proto);
JSHClass::NotifyHclassChanged(thread, hclass, newClass);
auto newClass = SetPrototypeWithNotification(thread, hclass, proto);
RestoreElementsKindToGeneric(*newClass);
object->SynchronizedSetClass(thread, *newClass);
thread->NotifyStableArrayElementsGuardians(object, StableArrayChangeKind::PROTO);

View File

@ -1995,9 +1995,9 @@ public:
ACCESSORS_PRIMITIVE_FIELD(BitField1, uint32_t, BIT_FIELD1_OFFSET, LAST_OFFSET);
DEFINE_ALIGN_SIZE(LAST_OFFSET);
static JSHandle<JSTaggedValue> SetPrototypeWithNotification(const JSThread *thread,
const JSHandle<JSTaggedValue> &hclass,
const JSHandle<JSTaggedValue> &proto);
static JSHandle<JSHClass> SetPrototypeWithNotification(const JSThread *thread,
const JSHandle<JSHClass> &hclass,
const JSHandle<JSTaggedValue> &proto);
static void SetPrototypeTransition(JSThread *thread, const JSHandle<JSObject> &object,
const JSHandle<JSTaggedValue> &proto);
void SetPrototype(const JSThread *thread, JSTaggedValue proto);

View File

@ -234,6 +234,7 @@ group("ark_aot_ts_test") {
"pgo_math",
"pgo_math_round",
"pgo_objectliteral_operation",
"pgo_object_prototype",
"pgo_call_deopt_js",
"pgo_call_recursive_js",

View File

@ -0,0 +1,20 @@
# 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_js_test_action("pgo_object_prototype") {
deps = []
is_enable_pgo = true
is_enable_opt_inlining = true
}

View File

@ -0,0 +1,15 @@
# 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.
-1
50

View File

@ -0,0 +1,15 @@
# 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.
-1
50

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2024 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.
*/
var proto = {
method(x) {
return -1;
}
}
var object = {
method(x) {
return x;
}
}
Object.setPrototypeOf(object, proto);
// Check usage of proto's HClass after AOT compile
print(proto.method(50));
print(object.method(50));

View File

@ -159,6 +159,9 @@ class LogParser {
}
cutResult.push('inNum=[' + ir.in[0].length + ',' + ir.in[1].length + ',' + ir.in[2].length + ',' + ir.in[3].length + ',' + ir.in[4].length + ']');
cutResult.push('outNum=' + ir.out.length);
if ('comment' in ir) {
cutResult.push('//' + ir.comment);
}
ir.maxDetailWidth = 0;
for (let detail of cutResult) {
let w = X2DFast.gi().getTextWidth(detail, 14);
@ -427,4 +430,4 @@ class LogParser {
module.exports = {
LogParser
};
};