Maintain Subtyping when Adding Property on Prototype

Reduce some deoptimization in cocos.

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I77SBD

Signed-off-by: dingding <dingding5@huawei.com>
Change-Id: I1818d18fdf629d5f9d5e11d527e8280a0a414e5f
This commit is contained in:
dingding 2023-05-23 11:37:28 +08:00
parent 1c2e04399e
commit a47c0c72fb
5 changed files with 53 additions and 14 deletions

View File

@ -241,7 +241,7 @@ void JSHClass::AddProperty(const JSThread *thread, const JSHandle<JSObject> &obj
if (newClass != nullptr) {
obj->SetClass(newClass);
#if ECMASCRIPT_ENABLE_IC
JSHClass::NotifyHclassChanged(thread, jshclass, JSHandle<JSHClass>(thread, newClass));
JSHClass::NotifyHclassChanged(thread, jshclass, JSHandle<JSHClass>(thread, newClass), key.GetTaggedValue());
#endif
return;
}
@ -271,7 +271,7 @@ void JSHClass::AddProperty(const JSThread *thread, const JSHandle<JSObject> &obj
// 5. update hclass in object.
#if ECMASCRIPT_ENABLE_IC
JSHClass::NotifyHclassChanged(thread, jshclass, newJsHClass);
JSHClass::NotifyHclassChanged(thread, jshclass, newJsHClass, key.GetTaggedValue());
#endif
obj->SetClass(*newJsHClass);
@ -459,7 +459,8 @@ JSHandle<JSTaggedValue> JSHClass::EnableProtoChangeMarker(const JSThread *thread
return JSHandle<JSTaggedValue>(markerHandle);
}
void JSHClass::NotifyHclassChanged(const JSThread *thread, JSHandle<JSHClass> oldHclass, JSHandle<JSHClass> newHclass)
void JSHClass::NotifyHclassChanged(const JSThread *thread, JSHandle<JSHClass> oldHclass, JSHandle<JSHClass> newHclass,
JSTaggedValue addedKey)
{
if (!oldHclass->IsPrototype()) {
return;
@ -469,7 +470,7 @@ void JSHClass::NotifyHclassChanged(const JSThread *thread, JSHandle<JSHClass> ol
return;
}
newHclass->SetIsPrototype(true);
JSHClass::NoticeThroughChain(thread, oldHclass);
JSHClass::NoticeThroughChain(thread, oldHclass, addedKey);
JSHClass::RefreshUsers(thread, oldHclass, newHclass);
}
@ -556,8 +557,10 @@ JSHandle<ProtoChangeDetails> JSHClass::GetProtoChangeDetails(const JSThread *thr
return GetProtoChangeDetails(thread, jshclass);
}
void JSHClass::MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
void JSHClass::MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
JSTaggedValue addedKey)
{
DISALLOW_GARBAGE_COLLECTION;
ASSERT(jshclass->IsPrototype() || jshclass->HasTSSubtyping());
JSTaggedValue markerValue = jshclass->GetProtoChangeMarker();
if (markerValue.IsProtoChangeMarker()) {
@ -565,14 +568,19 @@ void JSHClass::MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass>
protoChangeMarker->SetHasChanged(true);
}
if (jshclass->HasTSSubtyping()) {
jshclass->InitTSInheritInfo(thread);
if (jshclass->HasTSSubtyping() && addedKey.IsString()) {
JSHandle<JSTaggedValue> key(thread, addedKey);
if (!SubtypingOperator::TryMaintainTSSubtypingOnPrototype(thread, jshclass, key)) {
jshclass->InitTSInheritInfo(thread);
}
}
}
void JSHClass::NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
void JSHClass::NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
JSTaggedValue addedKey)
{
MarkProtoChanged(thread, jshclass);
DISALLOW_GARBAGE_COLLECTION;
MarkProtoChanged(thread, jshclass, addedKey);
JSTaggedValue protoDetailsValue = jshclass->GetProtoChangeDetails();
if (!protoDetailsValue.IsProtoChangeDetails()) {
return;
@ -585,7 +593,7 @@ void JSHClass::NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClas
for (uint32_t i = 0; i < listeners->GetEnd(); i++) {
JSTaggedValue temp = listeners->Get(i);
if (temp.IsJSHClass()) {
NoticeThroughChain(thread, JSHandle<JSHClass>(thread, listeners->Get(i).GetTaggedObject()));
NoticeThroughChain(thread, JSHandle<JSHClass>(thread, listeners->Get(i).GetTaggedObject()), addedKey);
}
}
}

View File

@ -348,7 +348,8 @@ public:
static JSHandle<JSTaggedValue> EnableProtoChangeMarker(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
static void NotifyHclassChanged(const JSThread *thread, JSHandle<JSHClass> oldHclass, JSHandle<JSHClass> newHclass);
static void NotifyHclassChanged(const JSThread *thread, JSHandle<JSHClass> oldHclass, JSHandle<JSHClass> newHclass,
JSTaggedValue addedKey = JSTaggedValue::Undefined());
static void RegisterOnProtoChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
@ -362,9 +363,11 @@ public:
inline void UpdatePropertyMetaData(const JSThread *thread, const JSTaggedValue &key,
const PropertyAttributes &metaData);
static void MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
static void MarkProtoChanged(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
JSTaggedValue addedKey = JSTaggedValue::Undefined());
static void NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
static void NoticeThroughChain(const JSThread *thread, const JSHandle<JSHClass> &jshclass,
JSTaggedValue addedKey = JSTaggedValue::Undefined());
static void RefreshUsers(const JSThread *thread, const JSHandle<JSHClass> &oldHclass,
const JSHandle<JSHClass> &newHclass);

View File

@ -236,4 +236,28 @@ void SubtypingOperator::TryMaintainTSSubtyping(const JSThread *thread, const JSH
JSHClass::CopyTSInheritInfo(thread, oldHClass, newHClass);
}
// when add property on prototype, try maintain.
bool SubtypingOperator::TryMaintainTSSubtypingOnPrototype(const JSThread *thread, const JSHandle<JSHClass> &hclass,
const JSHandle<JSTaggedValue> &key)
{
ASSERT(key->IsString());
JSHandle<VTable> vtable(thread, hclass->GetVTable());
ASSERT(vtable->GetNumberOfTuples() > 0); // there have default key 'constructor' at least
if (vtable->Find(key.GetTaggedValue())) { // new key shadows vtable property
LOG_ECMA(DEBUG) << "TryMaintainTSSubtypingOnPrototype failed, key: "
<< ConvertToString(EcmaString::Cast(key->GetTaggedObject()));
return false;
}
int entry = JSHClass::FindPropertyEntry(thread, *hclass, key.GetTaggedValue());
if (entry != -1) { // new key shadows loacl property
LOG_ECMA(DEBUG) << "TryMaintainTSSubtypingOnPrototype failed, key: "
<< ConvertToString(EcmaString::Cast(key->GetTaggedObject()));
return false;
}
return true;
}
} // namespace panda::ecmascript

View File

@ -37,6 +37,10 @@ public:
static void TryMaintainTSSubtyping(const JSThread *thread, const JSHandle<JSHClass> &oldHClass,
JSHandle<JSHClass> &newHClass, const JSHandle<JSTaggedValue> &key);
static bool TryMaintainTSSubtypingOnPrototype(const JSThread *thread, const JSHandle<JSHClass> &hclass,
const JSHandle<JSTaggedValue> &key);
private:
static constexpr uint8_t MAX_LEVEL = 1 << JSHClass::LEVEL_BTTFIELD_NUM;

View File

@ -17,7 +17,7 @@ true
z
123
456
false
true
1
2
z