mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 01:59:58 +00:00
Opt TraceIC
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IB32C4 Signed-off-by: dov1s <maojunwei1@huawei.com> Change-Id: I2fd7b34302b2fb1444c8148857e5a521fcdef107
This commit is contained in:
parent
36a96121f4
commit
a5db84bf35
1
BUILD.gn
1
BUILD.gn
@ -722,6 +722,7 @@ ecma_source = [
|
|||||||
"ecmascript/async_generator_helper.cpp",
|
"ecmascript/async_generator_helper.cpp",
|
||||||
"ecmascript/global_env.cpp",
|
"ecmascript/global_env.cpp",
|
||||||
"ecmascript/global_env_constants.cpp",
|
"ecmascript/global_env_constants.cpp",
|
||||||
|
"ecmascript/ic/ic_handler.cpp",
|
||||||
"ecmascript/ic/ic_runtime.cpp",
|
"ecmascript/ic/ic_runtime.cpp",
|
||||||
"ecmascript/ic/profile_type_info.cpp",
|
"ecmascript/ic/profile_type_info.cpp",
|
||||||
"ecmascript/ic/property_box.cpp",
|
"ecmascript/ic/property_box.cpp",
|
||||||
|
@ -34,6 +34,7 @@ namespace panda::ecmascript {
|
|||||||
#define ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER 0
|
#define ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER 0
|
||||||
#define ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC 0
|
#define ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC 0
|
||||||
#define ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT 0
|
#define ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT 0
|
||||||
|
#define ECMASCRIPT_ENABLE_TRACE_IC 0
|
||||||
|
|
||||||
#define ENABLE_NEXT_OPTIMIZATION 1
|
#define ENABLE_NEXT_OPTIMIZATION 1
|
||||||
|
|
||||||
|
333
ecmascript/ic/ic_handler.cpp
Normal file
333
ecmascript/ic/ic_handler.cpp
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ecmascript/ic/ic_handler.h"
|
||||||
|
#include "ecmascript/global_env_constants-inl.h"
|
||||||
|
|
||||||
|
namespace panda::ecmascript {
|
||||||
|
|
||||||
|
JSHandle<JSTaggedValue> LoadHandler::LoadProperty(const JSThread *thread, const ObjectOperator &op)
|
||||||
|
{
|
||||||
|
uint64_t handler = 0;
|
||||||
|
ASSERT(!op.IsElement());
|
||||||
|
if (!op.IsFound()) {
|
||||||
|
KindBit::Set<uint64_t>(HandlerKind::NON_EXIST, &handler);
|
||||||
|
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
||||||
|
}
|
||||||
|
ASSERT(op.IsFastMode());
|
||||||
|
|
||||||
|
JSTaggedValue val = op.GetValue();
|
||||||
|
if (val.IsPropertyBox()) {
|
||||||
|
return JSHandle<JSTaggedValue>(thread, val);
|
||||||
|
}
|
||||||
|
bool hasAccessor = op.IsAccessorDescriptor();
|
||||||
|
AccessorBit::Set<uint64_t>(hasAccessor, &handler);
|
||||||
|
|
||||||
|
if (!hasAccessor) {
|
||||||
|
JSHandle<JSTaggedValue> receiver = op.GetReceiver();
|
||||||
|
if (receiver->IsString()) {
|
||||||
|
JSTaggedValue lenKey = thread->GlobalConstants()->GetLengthString();
|
||||||
|
JSHandle<JSTaggedValue> key = op.GetKey();
|
||||||
|
EcmaString *proKey = key->IsString() ? EcmaString::Cast(key->GetTaggedObject()) : nullptr;
|
||||||
|
if (EcmaStringAccessor::StringsAreEqual(proKey, EcmaString::Cast(lenKey.GetTaggedObject()))) {
|
||||||
|
KindBit::Set<uint64_t>(HandlerKind::STRING_LENGTH, &handler);
|
||||||
|
} else {
|
||||||
|
KindBit::Set<uint64_t>(HandlerKind::STRING, &handler);
|
||||||
|
}
|
||||||
|
} else if (receiver->IsNumber()) {
|
||||||
|
KindBit::Set<uint64_t>(HandlerKind::NUMBER, &handler);
|
||||||
|
} else {
|
||||||
|
KindBit::Set<uint64_t>(HandlerKind::FIELD, &handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.IsInlinedProps()) {
|
||||||
|
InlinedPropsBit::Set<uint64_t>(true, &handler);
|
||||||
|
JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder());
|
||||||
|
auto index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
||||||
|
OffsetBit::Set<uint64_t>(index, &handler);
|
||||||
|
AttrIndexBit::Set<uint64_t>(op.GetIndex(), &handler);
|
||||||
|
RepresentationBit::Set<uint64_t>(op.GetRepresentation(), &handler);
|
||||||
|
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
||||||
|
}
|
||||||
|
if (op.IsFastMode()) {
|
||||||
|
JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder());
|
||||||
|
uint32_t inlinePropNum = holder->GetJSHClass()->GetInlinedProperties();
|
||||||
|
AttrIndexBit::Set<uint64_t>(op.GetIndex() + inlinePropNum, &handler);
|
||||||
|
OffsetBit::Set<uint64_t>(op.GetIndex(), &handler);
|
||||||
|
RepresentationBit::Set<uint64_t>(Representation::TAGGED, &handler);
|
||||||
|
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
||||||
|
}
|
||||||
|
LOG_ECMA(FATAL) << "this branch is unreachable";
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSHandle<JSTaggedValue> LoadHandler::LoadElement(const JSThread *thread, const ObjectOperator &op)
|
||||||
|
{
|
||||||
|
uint64_t handler = 0;
|
||||||
|
KindBit::Set<uint64_t>(HandlerKind::ELEMENT, &handler);
|
||||||
|
// To avoid logical errors and Deopt, temporarily skipping PGO Profiling.
|
||||||
|
// logical errors:
|
||||||
|
// When accessing an element of an object, AOT does not have a chain-climbing operation,
|
||||||
|
// so if the element is on a prototype, it will not be able to get the correct element.
|
||||||
|
// deopt:
|
||||||
|
// Currently there is no way to save the type of the key in pgo file, even if the type of the key
|
||||||
|
// is string, it will be treated as a number type by the AOT, leading to deopt at runtime.
|
||||||
|
if (op.GetReceiver() != op.GetHolder() || op.KeyFromStringType()) {
|
||||||
|
NeedSkipInPGODumpBit::Set<uint64_t>(true, &handler);
|
||||||
|
}
|
||||||
|
if (op.GetReceiver()->IsJSArray()) {
|
||||||
|
IsJSArrayBit::Set<uint64_t>(true, &handler);
|
||||||
|
}
|
||||||
|
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSHandle<JSTaggedValue> StoreHandler::StoreProperty(const JSThread *thread, const ObjectOperator &op)
|
||||||
|
{
|
||||||
|
uint64_t handler = 0;
|
||||||
|
JSHandle<JSObject> receiver = JSHandle<JSObject>::Cast(op.GetReceiver());
|
||||||
|
SFieldTypeBitSet(op, receiver, &handler);
|
||||||
|
if (op.IsElement()) {
|
||||||
|
SOutOfBoundsBit::Set<uint64_t>(op.GetElementOutOfBounds(), &handler);
|
||||||
|
return StoreElement(thread, op.GetReceiver(), handler);
|
||||||
|
}
|
||||||
|
JSTaggedValue val = op.GetValue();
|
||||||
|
if (val.IsPropertyBox()) {
|
||||||
|
return JSHandle<JSTaggedValue>(thread, val);
|
||||||
|
}
|
||||||
|
bool hasSetter = op.IsAccessorDescriptor();
|
||||||
|
AccessorBit::Set<uint64_t>(hasSetter, &handler);
|
||||||
|
if (!hasSetter) {
|
||||||
|
SKindBit::Set<uint64_t>(StoreHandlerKind::S_FIELD, &handler);
|
||||||
|
}
|
||||||
|
if (op.IsInlinedProps()) {
|
||||||
|
InlinedPropsBit::Set<uint64_t>(true, &handler);
|
||||||
|
uint32_t index = 0;
|
||||||
|
if (!hasSetter) {
|
||||||
|
index = receiver->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
||||||
|
} else {
|
||||||
|
JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder());
|
||||||
|
index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
||||||
|
}
|
||||||
|
AttrIndexBit::Set<uint64_t>(op.GetIndex(), &handler);
|
||||||
|
OffsetBit::Set<uint64_t>(index, &handler);
|
||||||
|
RepresentationBit::Set(op.GetRepresentation(), &handler);
|
||||||
|
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
||||||
|
}
|
||||||
|
ASSERT(op.IsFastMode());
|
||||||
|
uint32_t inlinePropNum = receiver->GetJSHClass()->GetInlinedProperties();
|
||||||
|
AttrIndexBit::Set<uint64_t>(op.GetIndex() + inlinePropNum, &handler);
|
||||||
|
OffsetBit::Set<uint64_t>(op.GetIndex(), &handler);
|
||||||
|
RepresentationBit::Set(Representation::TAGGED, &handler);
|
||||||
|
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSHandle<JSTaggedValue> TransitionHandler::StoreTransition(const JSThread *thread, const ObjectOperator &op)
|
||||||
|
{
|
||||||
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||||
|
JSHandle<TransitionHandler> handler = factory->NewTransitionHandler();
|
||||||
|
JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op);
|
||||||
|
handler->SetHandlerInfo(thread, handlerInfo);
|
||||||
|
auto hclass = JSObject::Cast(op.GetReceiver()->GetTaggedObject())->GetJSHClass();
|
||||||
|
handler->SetTransitionHClass(thread, JSTaggedValue(hclass));
|
||||||
|
return JSHandle<JSTaggedValue>::Cast(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSHandle<JSTaggedValue> PrototypeHandler::LoadPrototype(const JSThread *thread, const ObjectOperator &op,
|
||||||
|
const JSHandle<JSHClass> &hclass)
|
||||||
|
{
|
||||||
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||||
|
JSHandle<JSTaggedValue> handlerInfo = LoadHandler::LoadProperty(thread, op);
|
||||||
|
JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler();
|
||||||
|
handler->SetHandlerInfo(thread, handlerInfo);
|
||||||
|
if (op.IsFound()) {
|
||||||
|
handler->SetHolder(thread, op.GetHolder());
|
||||||
|
}
|
||||||
|
if (op.IsAccessorDescriptor()) {
|
||||||
|
JSTaggedValue result = op.GetValue();
|
||||||
|
if (result.IsPropertyBox()) {
|
||||||
|
result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
|
||||||
|
}
|
||||||
|
AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject());
|
||||||
|
if (!accessor->IsInternal()) {
|
||||||
|
JSTaggedValue getter = accessor->GetGetter();
|
||||||
|
if (!getter.IsUndefined()) {
|
||||||
|
JSHandle<JSFunction> func(thread, getter);
|
||||||
|
uint32_t methodOffset = Method::Cast(func->GetMethod())->GetMethodId().GetOffset();
|
||||||
|
handler->SetAccessorMethodId(methodOffset);
|
||||||
|
handler->SetAccessorJSFunction(thread, getter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ShareToLocal is prohibited
|
||||||
|
if (!hclass->IsJSShared()) {
|
||||||
|
auto result = JSHClass::EnableProtoChangeMarker(thread, hclass);
|
||||||
|
handler->SetProtoCell(thread, result);
|
||||||
|
}
|
||||||
|
return JSHandle<JSTaggedValue>::Cast(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSHandle<JSTaggedValue> PrototypeHandler::StorePrototype(const JSThread *thread, const ObjectOperator &op,
|
||||||
|
const JSHandle<JSHClass> &hclass)
|
||||||
|
{
|
||||||
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||||
|
JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler();
|
||||||
|
JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op);
|
||||||
|
handler->SetHandlerInfo(thread, handlerInfo);
|
||||||
|
handler->SetHolder(thread, op.GetHolder());
|
||||||
|
if (op.IsAccessorDescriptor()) {
|
||||||
|
JSTaggedValue result = op.GetValue();
|
||||||
|
if (result.IsPropertyBox()) {
|
||||||
|
result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
|
||||||
|
}
|
||||||
|
AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject());
|
||||||
|
if (!accessor->IsInternal() && accessor->HasSetter()) {
|
||||||
|
JSTaggedValue setter = accessor->GetSetter();
|
||||||
|
JSHandle<JSFunction> func(thread, setter);
|
||||||
|
handler->SetAccessorMethodId(
|
||||||
|
Method::Cast(func->GetMethod())->GetMethodId().GetOffset());
|
||||||
|
handler->SetAccessorJSFunction(thread, setter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ShareToLocal is prohibited
|
||||||
|
if (!hclass->IsJSShared()) {
|
||||||
|
auto result = JSHClass::EnableProtoChangeMarker(thread, hclass);
|
||||||
|
handler->SetProtoCell(thread, result);
|
||||||
|
}
|
||||||
|
return JSHandle<JSTaggedValue>::Cast(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSHandle<JSTaggedValue> TransWithProtoHandler::StoreTransition(const JSThread *thread, const ObjectOperator &op,
|
||||||
|
const JSHandle<JSHClass> &hclass)
|
||||||
|
{
|
||||||
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||||
|
JSHandle<TransWithProtoHandler> handler = factory->NewTransWithProtoHandler();
|
||||||
|
JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op);
|
||||||
|
handler->SetHandlerInfo(thread, handlerInfo);
|
||||||
|
auto result = JSHClass::EnableProtoChangeMarker(thread, hclass);
|
||||||
|
handler->SetProtoCell(thread, result);
|
||||||
|
handler->SetTransitionHClass(thread, hclass.GetTaggedValue());
|
||||||
|
|
||||||
|
return JSHandle<JSTaggedValue>::Cast(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerBase::PrintLoadHandler([[maybe_unused]] uint64_t handler, [[maybe_unused]] std::ostream& os)
|
||||||
|
{
|
||||||
|
#if ECMASCRIPT_ENABLE_TRACE_IC
|
||||||
|
HandlerKind kind = GetKind(handler);
|
||||||
|
os << "kind = ";
|
||||||
|
switch (kind) {
|
||||||
|
case HandlerKind::NONE:
|
||||||
|
os << "NONE"
|
||||||
|
<< ", is InlinedPropsBit = "
|
||||||
|
<< InlinedPropsBit::Get(handler)
|
||||||
|
<< ", is AccessorBit = "
|
||||||
|
<< AccessorBit::Get(handler)
|
||||||
|
<< ", OffsetBit = "
|
||||||
|
<< OffsetBit::Get(handler)
|
||||||
|
<< ", AttrIndexBit = "
|
||||||
|
<< AttrIndexBit::Get(handler);
|
||||||
|
break;
|
||||||
|
case HandlerKind::FIELD:
|
||||||
|
os << "FIELD"
|
||||||
|
<< ", is InlinedPropsBit = "
|
||||||
|
<< InlinedPropsBit::Get(handler)
|
||||||
|
<< ", is AccessorBit = "
|
||||||
|
<< AccessorBit::Get(handler)
|
||||||
|
<< ", OffsetBit = "
|
||||||
|
<< OffsetBit::Get(handler)
|
||||||
|
<< ", AttrIndexBit = "
|
||||||
|
<< AttrIndexBit::Get(handler);
|
||||||
|
break;
|
||||||
|
case HandlerKind::ELEMENT:
|
||||||
|
os << "ELEMENT"
|
||||||
|
<< ", is JSArray = "
|
||||||
|
<< IsJSArrayBit::Get(handler);
|
||||||
|
break;
|
||||||
|
case HandlerKind::DICTIONARY:
|
||||||
|
os << "DICTIONARY";
|
||||||
|
break;
|
||||||
|
case HandlerKind::STRING:
|
||||||
|
os << "STRING";
|
||||||
|
break;
|
||||||
|
case HandlerKind::STRING_LENGTH:
|
||||||
|
os << "STRING_LENGTH";
|
||||||
|
break;
|
||||||
|
case HandlerKind::TYPED_ARRAY:
|
||||||
|
os << "TYPED_ARRAY,"
|
||||||
|
<< "is OnHeap = "
|
||||||
|
<< IsOnHeapBit::Get(handler);
|
||||||
|
break;
|
||||||
|
case HandlerKind::NUMBER:
|
||||||
|
os << "NUMBER";
|
||||||
|
break;
|
||||||
|
case HandlerKind::NON_EXIST:
|
||||||
|
os << "NON_EXIST";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
os << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlerBase::PrintStoreHandler([[maybe_unused]] uint64_t handler, [[maybe_unused]] std::ostream& os)
|
||||||
|
{
|
||||||
|
#if ECMASCRIPT_ENABLE_TRACE_IC
|
||||||
|
StoreHandlerKind kind = static_cast<StoreHandlerKind>(GetKind(handler));
|
||||||
|
os << "kind = ";
|
||||||
|
switch (kind) {
|
||||||
|
case StoreHandlerKind::S_NONE:
|
||||||
|
os << "NONE"
|
||||||
|
<< ", is InlinedPropsBit = "
|
||||||
|
<< InlinedPropsBit::Get(handler)
|
||||||
|
<< ", is AccessorBit = "
|
||||||
|
<< AccessorBit::Get(handler)
|
||||||
|
<< ", OffsetBit = "
|
||||||
|
<< OffsetBit::Get(handler)
|
||||||
|
<< ", AttrIndexBit = "
|
||||||
|
<< AttrIndexBit::Get(handler)
|
||||||
|
<< ", SFieldTypeBit = "
|
||||||
|
<< static_cast<uint32_t>(SFieldTypeBit::Get(handler));
|
||||||
|
break;
|
||||||
|
case StoreHandlerKind::S_FIELD:
|
||||||
|
os << "S_FIELD"
|
||||||
|
<< ", is InlinedPropsBit = "
|
||||||
|
<< InlinedPropsBit::Get(handler)
|
||||||
|
<< ", is AccessorBit = "
|
||||||
|
<< AccessorBit::Get(handler)
|
||||||
|
<< ", OffsetBit = "
|
||||||
|
<< OffsetBit::Get(handler)
|
||||||
|
<< ", AttrIndexBit = "
|
||||||
|
<< AttrIndexBit::Get(handler)
|
||||||
|
<< ", SFieldTypeBit = "
|
||||||
|
<< static_cast<uint32_t>(SFieldTypeBit::Get(handler));
|
||||||
|
break;
|
||||||
|
case StoreHandlerKind::S_ELEMENT:
|
||||||
|
os << "S_ELEMENT"
|
||||||
|
<< ", is JSArray = "
|
||||||
|
<< IsJSArrayBit::Get(handler)
|
||||||
|
<< ", SOutOfBoundsBit = "
|
||||||
|
<< SOutOfBoundsBit::Get(handler)
|
||||||
|
<< ", SFieldTypeBit = "
|
||||||
|
<< static_cast<uint32_t>(SFieldTypeBit::Get(handler));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
os << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace panda::ecmascript
|
@ -194,85 +194,15 @@ public:
|
|||||||
{
|
{
|
||||||
return IsOnHeapBit::Get(handler);
|
return IsOnHeapBit::Get(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void PrintLoadHandler(uint64_t handler, std::ostream& os);
|
||||||
|
static void PrintStoreHandler(uint64_t handler, std::ostream& os);
|
||||||
};
|
};
|
||||||
|
|
||||||
class LoadHandler final : public HandlerBase {
|
class LoadHandler final : public HandlerBase {
|
||||||
public:
|
public:
|
||||||
static inline JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op)
|
static JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op);
|
||||||
{
|
static JSHandle<JSTaggedValue> LoadElement(const JSThread *thread, const ObjectOperator &op);
|
||||||
uint64_t handler = 0;
|
|
||||||
ASSERT(!op.IsElement());
|
|
||||||
if (!op.IsFound()) {
|
|
||||||
KindBit::Set<uint64_t>(HandlerKind::NON_EXIST, &handler);
|
|
||||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
|
||||||
}
|
|
||||||
ASSERT(op.IsFastMode());
|
|
||||||
|
|
||||||
JSTaggedValue val = op.GetValue();
|
|
||||||
if (val.IsPropertyBox()) {
|
|
||||||
return JSHandle<JSTaggedValue>(thread, val);
|
|
||||||
}
|
|
||||||
bool hasAccessor = op.IsAccessorDescriptor();
|
|
||||||
AccessorBit::Set<uint64_t>(hasAccessor, &handler);
|
|
||||||
|
|
||||||
if (!hasAccessor) {
|
|
||||||
JSHandle<JSTaggedValue> receiver = op.GetReceiver();
|
|
||||||
if (receiver->IsString()) {
|
|
||||||
JSTaggedValue lenKey = thread->GlobalConstants()->GetLengthString();
|
|
||||||
JSHandle<JSTaggedValue> key = op.GetKey();
|
|
||||||
EcmaString *proKey = key->IsString() ? EcmaString::Cast(key->GetTaggedObject()) : nullptr;
|
|
||||||
if (EcmaStringAccessor::StringsAreEqual(proKey, EcmaString::Cast(lenKey.GetTaggedObject()))) {
|
|
||||||
KindBit::Set<uint64_t>(HandlerKind::STRING_LENGTH, &handler);
|
|
||||||
} else {
|
|
||||||
KindBit::Set<uint64_t>(HandlerKind::STRING, &handler);
|
|
||||||
}
|
|
||||||
} else if (receiver->IsNumber()) {
|
|
||||||
KindBit::Set<uint64_t>(HandlerKind::NUMBER, &handler);
|
|
||||||
} else {
|
|
||||||
KindBit::Set<uint64_t>(HandlerKind::FIELD, &handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.IsInlinedProps()) {
|
|
||||||
InlinedPropsBit::Set<uint64_t>(true, &handler);
|
|
||||||
JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder());
|
|
||||||
auto index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
|
||||||
OffsetBit::Set<uint64_t>(index, &handler);
|
|
||||||
AttrIndexBit::Set<uint64_t>(op.GetIndex(), &handler);
|
|
||||||
RepresentationBit::Set<uint64_t>(op.GetRepresentation(), &handler);
|
|
||||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
|
||||||
}
|
|
||||||
if (op.IsFastMode()) {
|
|
||||||
JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder());
|
|
||||||
uint32_t inlinePropNum = holder->GetJSHClass()->GetInlinedProperties();
|
|
||||||
AttrIndexBit::Set<uint64_t>(op.GetIndex() + inlinePropNum, &handler);
|
|
||||||
OffsetBit::Set<uint64_t>(op.GetIndex(), &handler);
|
|
||||||
RepresentationBit::Set<uint64_t>(Representation::TAGGED, &handler);
|
|
||||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
|
||||||
}
|
|
||||||
LOG_ECMA(FATAL) << "this branch is unreachable";
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline JSHandle<JSTaggedValue> LoadElement(const JSThread *thread, const ObjectOperator &op)
|
|
||||||
{
|
|
||||||
uint64_t handler = 0;
|
|
||||||
KindBit::Set<uint64_t>(HandlerKind::ELEMENT, &handler);
|
|
||||||
// To avoid logical errors and Deopt, temporarily skipping PGO Profiling.
|
|
||||||
// logical errors:
|
|
||||||
// When accessing an element of an object, AOT does not have a chain-climbing operation,
|
|
||||||
// so if the element is on a prototype, it will not be able to get the correct element.
|
|
||||||
// deopt:
|
|
||||||
// Currently there is no way to save the type of the key in pgo file, even if the type of the key
|
|
||||||
// is string, it will be treated as a number type by the AOT, leading to deopt at runtime.
|
|
||||||
if (op.GetReceiver() != op.GetHolder() || op.KeyFromStringType()) {
|
|
||||||
NeedSkipInPGODumpBit::Set<uint64_t>(true, &handler);
|
|
||||||
}
|
|
||||||
if (op.GetReceiver()->IsJSArray()) {
|
|
||||||
IsJSArrayBit::Set<uint64_t>(true, &handler);
|
|
||||||
}
|
|
||||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline JSHandle<JSTaggedValue> LoadStringElement(const JSThread *thread)
|
static inline JSHandle<JSTaggedValue> LoadStringElement(const JSThread *thread)
|
||||||
{
|
{
|
||||||
@ -293,45 +223,7 @@ public:
|
|||||||
|
|
||||||
class StoreHandler final : public HandlerBase {
|
class StoreHandler final : public HandlerBase {
|
||||||
public:
|
public:
|
||||||
static inline JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op)
|
static JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op);
|
||||||
{
|
|
||||||
uint64_t handler = 0;
|
|
||||||
JSHandle<JSObject> receiver = JSHandle<JSObject>::Cast(op.GetReceiver());
|
|
||||||
SFieldTypeBitSet(op, receiver, &handler);
|
|
||||||
if (op.IsElement()) {
|
|
||||||
SOutOfBoundsBit::Set<uint64_t>(op.GetElementOutOfBounds(), &handler);
|
|
||||||
return StoreElement(thread, op.GetReceiver(), handler);
|
|
||||||
}
|
|
||||||
JSTaggedValue val = op.GetValue();
|
|
||||||
if (val.IsPropertyBox()) {
|
|
||||||
return JSHandle<JSTaggedValue>(thread, val);
|
|
||||||
}
|
|
||||||
bool hasSetter = op.IsAccessorDescriptor();
|
|
||||||
AccessorBit::Set<uint64_t>(hasSetter, &handler);
|
|
||||||
if (!hasSetter) {
|
|
||||||
SKindBit::Set<uint64_t>(StoreHandlerKind::S_FIELD, &handler);
|
|
||||||
}
|
|
||||||
if (op.IsInlinedProps()) {
|
|
||||||
InlinedPropsBit::Set<uint64_t>(true, &handler);
|
|
||||||
uint32_t index = 0;
|
|
||||||
if (!hasSetter) {
|
|
||||||
index = receiver->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
|
||||||
} else {
|
|
||||||
JSHandle<JSObject> holder = JSHandle<JSObject>::Cast(op.GetHolder());
|
|
||||||
index = holder->GetJSHClass()->GetInlinedPropertiesIndex(op.GetIndex());
|
|
||||||
}
|
|
||||||
AttrIndexBit::Set<uint64_t>(op.GetIndex(), &handler);
|
|
||||||
OffsetBit::Set<uint64_t>(index, &handler);
|
|
||||||
RepresentationBit::Set(op.GetRepresentation(), &handler);
|
|
||||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
|
||||||
}
|
|
||||||
ASSERT(op.IsFastMode());
|
|
||||||
uint32_t inlinePropNum = receiver->GetJSHClass()->GetInlinedProperties();
|
|
||||||
AttrIndexBit::Set<uint64_t>(op.GetIndex() + inlinePropNum, &handler);
|
|
||||||
OffsetBit::Set<uint64_t>(op.GetIndex(), &handler);
|
|
||||||
RepresentationBit::Set(Representation::TAGGED, &handler);
|
|
||||||
return JSHandle<JSTaggedValue>(thread, JSTaggedValue::WrapUint64(handler));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread,
|
static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread,
|
||||||
JSHandle<JSTaggedValue> receiver, uint64_t handler)
|
JSHandle<JSTaggedValue> receiver, uint64_t handler)
|
||||||
@ -364,16 +256,7 @@ public:
|
|||||||
return static_cast<TransitionHandler *>(object);
|
return static_cast<TransitionHandler *>(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op)
|
static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op);
|
||||||
{
|
|
||||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
||||||
JSHandle<TransitionHandler> handler = factory->NewTransitionHandler();
|
|
||||||
JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op);
|
|
||||||
handler->SetHandlerInfo(thread, handlerInfo);
|
|
||||||
auto hclass = JSObject::Cast(op.GetReceiver()->GetTaggedObject())->GetJSHClass();
|
|
||||||
handler->SetTransitionHClass(thread, JSTaggedValue(hclass));
|
|
||||||
return JSHandle<JSTaggedValue>::Cast(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
||||||
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
|
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
|
||||||
@ -391,68 +274,10 @@ public:
|
|||||||
return static_cast<PrototypeHandler *>(object);
|
return static_cast<PrototypeHandler *>(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op,
|
static JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op,
|
||||||
const JSHandle<JSHClass> &hclass)
|
const JSHandle<JSHClass> &hclass);
|
||||||
{
|
static JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op,
|
||||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
const JSHandle<JSHClass> &hclass);
|
||||||
JSHandle<JSTaggedValue> handlerInfo = LoadHandler::LoadProperty(thread, op);
|
|
||||||
JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler();
|
|
||||||
handler->SetHandlerInfo(thread, handlerInfo);
|
|
||||||
if (op.IsFound()) {
|
|
||||||
handler->SetHolder(thread, op.GetHolder());
|
|
||||||
}
|
|
||||||
if (op.IsAccessorDescriptor()) {
|
|
||||||
JSTaggedValue result = op.GetValue();
|
|
||||||
if (result.IsPropertyBox()) {
|
|
||||||
result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
|
|
||||||
}
|
|
||||||
AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject());
|
|
||||||
if (!accessor->IsInternal()) {
|
|
||||||
JSTaggedValue getter = accessor->GetGetter();
|
|
||||||
if (!getter.IsUndefined()) {
|
|
||||||
JSHandle<JSFunction> func(thread, getter);
|
|
||||||
uint32_t methodOffset = Method::Cast(func->GetMethod())->GetMethodId().GetOffset();
|
|
||||||
handler->SetAccessorMethodId(methodOffset);
|
|
||||||
handler->SetAccessorJSFunction(thread, getter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ShareToLocal is prohibited
|
|
||||||
if (!hclass->IsJSShared()) {
|
|
||||||
auto result = JSHClass::EnableProtoChangeMarker(thread, hclass);
|
|
||||||
handler->SetProtoCell(thread, result);
|
|
||||||
}
|
|
||||||
return JSHandle<JSTaggedValue>::Cast(handler);
|
|
||||||
}
|
|
||||||
static inline JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op,
|
|
||||||
const JSHandle<JSHClass> &hclass)
|
|
||||||
{
|
|
||||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
||||||
JSHandle<PrototypeHandler> handler = factory->NewPrototypeHandler();
|
|
||||||
JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op);
|
|
||||||
handler->SetHandlerInfo(thread, handlerInfo);
|
|
||||||
handler->SetHolder(thread, op.GetHolder());
|
|
||||||
if (op.IsAccessorDescriptor()) {
|
|
||||||
JSTaggedValue result = op.GetValue();
|
|
||||||
if (result.IsPropertyBox()) {
|
|
||||||
result = PropertyBox::Cast(result.GetTaggedObject())->GetValue();
|
|
||||||
}
|
|
||||||
AccessorData *accessor = AccessorData::Cast(result.GetTaggedObject());
|
|
||||||
if (!accessor->IsInternal() && accessor->HasSetter()) {
|
|
||||||
JSTaggedValue setter = accessor->GetSetter();
|
|
||||||
JSHandle<JSFunction> func(thread, setter);
|
|
||||||
handler->SetAccessorMethodId(
|
|
||||||
Method::Cast(func->GetMethod())->GetMethodId().GetOffset());
|
|
||||||
handler->SetAccessorJSFunction(thread, setter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ShareToLocal is prohibited
|
|
||||||
if (!hclass->IsJSShared()) {
|
|
||||||
auto result = JSHClass::EnableProtoChangeMarker(thread, hclass);
|
|
||||||
handler->SetProtoCell(thread, result);
|
|
||||||
}
|
|
||||||
return JSHandle<JSTaggedValue>::Cast(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
||||||
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
|
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
|
||||||
@ -474,19 +299,8 @@ public:
|
|||||||
return static_cast<TransWithProtoHandler *>(object);
|
return static_cast<TransWithProtoHandler *>(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op,
|
static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op,
|
||||||
const JSHandle<JSHClass> &hclass)
|
const JSHandle<JSHClass> &hclass);
|
||||||
{
|
|
||||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
||||||
JSHandle<TransWithProtoHandler> handler = factory->NewTransWithProtoHandler();
|
|
||||||
JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op);
|
|
||||||
handler->SetHandlerInfo(thread, handlerInfo);
|
|
||||||
auto result = JSHClass::EnableProtoChangeMarker(thread, hclass);
|
|
||||||
handler->SetProtoCell(thread, result);
|
|
||||||
handler->SetTransitionHClass(thread, hclass.GetTaggedValue());
|
|
||||||
|
|
||||||
return JSHandle<JSTaggedValue>::Cast(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
||||||
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
|
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
|
||||||
@ -505,19 +319,6 @@ public:
|
|||||||
return static_cast<StoreAOTHandler *>(object);
|
return static_cast<StoreAOTHandler *>(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline JSHandle<JSTaggedValue> StoreAOT(const JSThread *thread, const ObjectOperator &op,
|
|
||||||
const JSHandle<JSHClass> &hclass)
|
|
||||||
{
|
|
||||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
||||||
JSHandle<StoreAOTHandler> handler = factory->NewStoreAOTHandler();
|
|
||||||
JSHandle<JSTaggedValue> handlerInfo = StoreHandler::StoreProperty(thread, op);
|
|
||||||
handler->SetHandlerInfo(thread, handlerInfo);
|
|
||||||
handler->SetHolder(thread, op.GetHolder());
|
|
||||||
auto result = JSHClass::EnableProtoChangeMarker(thread, hclass);
|
|
||||||
handler->SetProtoCell(thread, result);
|
|
||||||
return JSHandle<JSTaggedValue>::Cast(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
|
||||||
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
|
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
|
||||||
ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET)
|
ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET)
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
|
|
||||||
#include "ecmascript/ic/ic_runtime.h"
|
#include "ecmascript/ic/ic_runtime.h"
|
||||||
#include "ecmascript/ic/ic_handler.h"
|
#include "ecmascript/ic/ic_handler.h"
|
||||||
|
#include "ecmascript/dfx/stackinfo/js_stackinfo.h"
|
||||||
#include "ecmascript/interpreter/interpreter.h"
|
#include "ecmascript/interpreter/interpreter.h"
|
||||||
#include "ecmascript/interpreter/slow_runtime_stub.h"
|
#include "ecmascript/interpreter/slow_runtime_stub.h"
|
||||||
#include "ecmascript/js_primitive_ref.h"
|
#include "ecmascript/js_primitive_ref.h"
|
||||||
#include "ecmascript/shared_objects/js_shared_array.h"
|
#include "ecmascript/shared_objects/js_shared_array.h"
|
||||||
|
|
||||||
namespace panda::ecmascript {
|
namespace panda::ecmascript {
|
||||||
#define TRACE_IC 0 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
|
||||||
|
|
||||||
void ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
|
void ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
|
||||||
JSHandle<JSTaggedValue> receiver)
|
JSHandle<JSTaggedValue> receiver)
|
||||||
@ -152,25 +152,6 @@ void ICRuntime::UpdateStoreHandler(const ObjectOperator &op, JSHandle<JSTaggedVa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ICRuntime::TraceIC([[maybe_unused]] JSHandle<JSTaggedValue> receiver,
|
|
||||||
[[maybe_unused]] JSHandle<JSTaggedValue> key) const
|
|
||||||
{
|
|
||||||
#if TRACE_IC
|
|
||||||
auto kind = ICKindToString(GetICKind());
|
|
||||||
auto state = ProfileTypeAccessor::ICStateToString(icAccessor_.GetICState());
|
|
||||||
if (key->IsString()) {
|
|
||||||
auto keyStrHandle = JSHandle<EcmaString>::Cast(key);
|
|
||||||
LOG_ECMA(ERROR) << kind << " miss key is: " << EcmaStringAccessor(keyStrHandle).ToCString()
|
|
||||||
<< ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
|
|
||||||
<< ", state is " << state;
|
|
||||||
} else {
|
|
||||||
LOG_ECMA(ERROR) << kind << " miss " << ", state is "
|
|
||||||
<< ", receiver is " << receiver->GetTaggedObject()->GetClass()->IsDictionaryMode()
|
|
||||||
<< state;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
|
JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key)
|
||||||
{
|
{
|
||||||
JSTaggedValue::RequireObjectCoercible(thread_, receiver, "Cannot load property of null or undefined");
|
JSTaggedValue::RequireObjectCoercible(thread_, receiver, "Cannot load property of null or undefined");
|
||||||
@ -210,7 +191,7 @@ JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSH
|
|||||||
icAccessor_.SetAsMega();
|
icAccessor_.SetAsMega();
|
||||||
return result.GetTaggedValue();
|
return result.GetTaggedValue();
|
||||||
}
|
}
|
||||||
TraceIC(receiver, key);
|
TraceIC(GetThread(), receiver, key);
|
||||||
// do not cache element
|
// do not cache element
|
||||||
if (!op.IsFastMode()) {
|
if (!op.IsFastMode()) {
|
||||||
icAccessor_.SetAsMega();
|
icAccessor_.SetAsMega();
|
||||||
@ -261,7 +242,7 @@ JSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle
|
|||||||
icAccessor_.SetAsMega();
|
icAccessor_.SetAsMega();
|
||||||
return result.GetTaggedValue();
|
return result.GetTaggedValue();
|
||||||
}
|
}
|
||||||
TraceIC(receiver, key);
|
TraceIC(GetThread(), receiver, key);
|
||||||
// do not cache element
|
// do not cache element
|
||||||
if (!op.IsFastMode()) {
|
if (!op.IsFastMode()) {
|
||||||
icAccessor_.SetAsMega();
|
icAccessor_.SetAsMega();
|
||||||
@ -320,7 +301,7 @@ JSTaggedValue LoadICRuntime::LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> rec
|
|||||||
icAccessor_.SetAsMega();
|
icAccessor_.SetAsMega();
|
||||||
return result.GetTaggedValue();
|
return result.GetTaggedValue();
|
||||||
}
|
}
|
||||||
TraceIC(receiver, key);
|
TraceIC(GetThread(), receiver, key);
|
||||||
// do not cache element
|
// do not cache element
|
||||||
if (!op.IsFastMode()) {
|
if (!op.IsFastMode()) {
|
||||||
icAccessor_.SetAsMega();
|
icAccessor_.SetAsMega();
|
||||||
@ -408,7 +389,7 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHand
|
|||||||
return JSTaggedValue::Undefined();
|
return JSTaggedValue::Undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceIC(receiver, key);
|
TraceIC(GetThread(), receiver, key);
|
||||||
if (success) {
|
if (success) {
|
||||||
UpdateStoreHandler(op, key, receiver);
|
UpdateStoreHandler(op, key, receiver);
|
||||||
}
|
}
|
||||||
@ -474,7 +455,7 @@ JSTaggedValue StoreICRuntime::StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> r
|
|||||||
return JSTaggedValue::Undefined();
|
return JSTaggedValue::Undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceIC(receiver, key);
|
TraceIC(GetThread(), receiver, key);
|
||||||
if (success) {
|
if (success) {
|
||||||
UpdateStoreHandler(op, key, receiver);
|
UpdateStoreHandler(op, key, receiver);
|
||||||
}
|
}
|
||||||
@ -494,4 +475,56 @@ JSTaggedValue StoreICRuntime::HandleAccesor(ObjectOperator *op, const JSHandle<J
|
|||||||
}
|
}
|
||||||
return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
|
return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ICRuntime::TraceIC([[maybe_unused]] JSThread *thread,
|
||||||
|
[[maybe_unused]] JSHandle<JSTaggedValue> receiver,
|
||||||
|
[[maybe_unused]] JSHandle<JSTaggedValue> key) const
|
||||||
|
{
|
||||||
|
#if ECMASCRIPT_ENABLE_TRACE_IC
|
||||||
|
// If BackTrace affects IC, can choose not to execute it.
|
||||||
|
std::string strTraceIC = "Miss Func BackTrace: ";
|
||||||
|
std::vector<JsFrameInfo> jsStackInfo = JsStackInfo::BuildJsStackInfo(thread, true);
|
||||||
|
if (jsStackInfo.empty()) {
|
||||||
|
strTraceIC += "empty";
|
||||||
|
} else {
|
||||||
|
JsFrameInfo jsFrameInfo = jsStackInfo.front();
|
||||||
|
size_t pos = jsFrameInfo.pos.find(':', 0);
|
||||||
|
if (pos != CString::npos) {
|
||||||
|
int lineNumber = std::stoi(jsFrameInfo.pos.substr(0, pos));
|
||||||
|
int columnNumber = std::stoi(jsFrameInfo.pos.substr(pos + 1));
|
||||||
|
auto sourceMapcb = thread->GetEcmaVM()->GetSourceMapTranslateCallback();
|
||||||
|
if (sourceMapcb != nullptr && !jsFrameInfo.fileName.empty()) {
|
||||||
|
sourceMapcb(jsFrameInfo.fileName, lineNumber, columnNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strTraceIC += "funcName: " + jsFrameInfo.functionName + ", url: " +
|
||||||
|
jsFrameInfo.fileName + ":" + jsFrameInfo.pos;
|
||||||
|
}
|
||||||
|
LOG_ECMA(ERROR) << strTraceIC;
|
||||||
|
|
||||||
|
auto kind = ICKindToString(GetICKind());
|
||||||
|
bool primitiveIc = false;
|
||||||
|
if (receiver->IsNumber() || receiver->IsString()) {
|
||||||
|
primitiveIc = true;
|
||||||
|
}
|
||||||
|
auto state = ProfileTypeAccessor::ICStateToString(icAccessor_.GetICState());
|
||||||
|
if (key->IsString()) {
|
||||||
|
auto keyStrHandle = JSHandle<EcmaString>::Cast(key);
|
||||||
|
LOG_ECMA(ERROR) << kind << " miss, key is: " << EcmaStringAccessor(keyStrHandle).ToCString()
|
||||||
|
<< ", icstate is: " << state
|
||||||
|
<< ", slotid is: " << GetSlotId();
|
||||||
|
} else {
|
||||||
|
LOG_ECMA(ERROR) << kind << " miss, "
|
||||||
|
<< ", icstate is " << state
|
||||||
|
<< ", slotid is:" << GetSlotId();
|
||||||
|
}
|
||||||
|
if (primitiveIc) {
|
||||||
|
LOG_ECMA(ERROR) << "primitiveIc ";
|
||||||
|
} else {
|
||||||
|
JSHClass *jshclass = receiver->GetTaggedObject()->GetClass();
|
||||||
|
LOG_ECMA(ERROR) << "receiver DictionaryMode is: " << jshclass->IsDictionaryMode()
|
||||||
|
<< ", hclass is: "<< std::hex << jshclass;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
} // namespace panda::ecmascript
|
} // namespace panda::ecmascript
|
||||||
|
@ -57,7 +57,12 @@ public:
|
|||||||
return icAccessor_.GetKind();
|
return icAccessor_.GetKind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraceIC(JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key) const;
|
uint32_t GetSlotId() const
|
||||||
|
{
|
||||||
|
return icAccessor_.GetSlotId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TraceIC(JSThread *thread, JSHandle<JSTaggedValue> receiver, JSHandle<JSTaggedValue> key) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
JSThread *thread_;
|
JSThread *thread_;
|
||||||
|
@ -223,6 +223,7 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::StoreICWithHandler(JSThread *thread, JST
|
|||||||
INTERPRETER_TRACE(thread, StoreICWithHandler);
|
INTERPRETER_TRACE(thread, StoreICWithHandler);
|
||||||
if (handler.IsInt()) {
|
if (handler.IsInt()) {
|
||||||
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
||||||
|
HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
|
||||||
if (HandlerBase::IsNonSharedStoreField(handlerInfo)) {
|
if (HandlerBase::IsNonSharedStoreField(handlerInfo)) {
|
||||||
StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
|
StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
|
||||||
return JSTaggedValue::Undefined();
|
return JSTaggedValue::Undefined();
|
||||||
@ -452,6 +453,7 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTa
|
|||||||
INTERPRETER_TRACE(thread, LoadICWithHandler);
|
INTERPRETER_TRACE(thread, LoadICWithHandler);
|
||||||
if (LIKELY(handler.IsInt())) {
|
if (LIKELY(handler.IsInt())) {
|
||||||
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
||||||
|
HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
|
||||||
if (LIKELY(HandlerBase::IsField(handlerInfo))) {
|
if (LIKELY(HandlerBase::IsField(handlerInfo))) {
|
||||||
return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
|
return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
|
||||||
}
|
}
|
||||||
@ -481,6 +483,7 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithElementHandler(JSThread *threa
|
|||||||
{
|
{
|
||||||
if (LIKELY(handler.IsInt())) {
|
if (LIKELY(handler.IsInt())) {
|
||||||
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
||||||
|
HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
|
||||||
if (HandlerBase::IsNormalElement(handlerInfo)) {
|
if (HandlerBase::IsNormalElement(handlerInfo)) {
|
||||||
return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
|
return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
|
||||||
} else if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
|
} else if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
|
||||||
@ -556,6 +559,7 @@ JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver,
|
|||||||
uint32_t elementIndex = static_cast<uint32_t>(index);
|
uint32_t elementIndex = static_cast<uint32_t>(index);
|
||||||
if (handler.IsInt()) {
|
if (handler.IsInt()) {
|
||||||
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
|
||||||
|
HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
|
||||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||||
JSHandle<JSObject> receiverHandle(thread, receiver);
|
JSHandle<JSObject> receiverHandle(thread, receiver);
|
||||||
JSHandle<JSTaggedValue> valueHandle(thread, value);
|
JSHandle<JSTaggedValue> valueHandle(thread, value);
|
||||||
|
@ -476,6 +476,11 @@ public:
|
|||||||
return kind_;
|
return kind_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t GetSlotId() const
|
||||||
|
{
|
||||||
|
return slotId_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JSThread* thread_;
|
JSThread* thread_;
|
||||||
JSHandle<ProfileTypeInfo> profileTypeInfo_;
|
JSHandle<ProfileTypeInfo> profileTypeInfo_;
|
||||||
|
@ -155,8 +155,8 @@ HWTEST_F_L0(ICRunTimeTest, TraceIC)
|
|||||||
JSHandle<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength);
|
JSHandle<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength);
|
||||||
|
|
||||||
ICRuntime icRuntime(thread, handleProfileTypeInfo, 4, ICKind::NamedGlobalLoadIC); // 4: means the NamedGlobalLoadIC
|
ICRuntime icRuntime(thread, handleProfileTypeInfo, 4, ICKind::NamedGlobalLoadIC); // 4: means the NamedGlobalLoadIC
|
||||||
icRuntime.TraceIC(handleReceiver, handleKeyWithString);
|
icRuntime.TraceIC(thread, handleReceiver, handleKeyWithString);
|
||||||
icRuntime.TraceIC(handleReceiver, handleKeyWithElement);
|
icRuntime.TraceIC(thread, handleReceiver, handleKeyWithElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
HWTEST_F_L0(ICRunTimeTest, StoreMiss)
|
HWTEST_F_L0(ICRunTimeTest, StoreMiss)
|
||||||
|
Loading…
Reference in New Issue
Block a user