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:
dov1s 2024-11-08 17:47:48 +08:00
parent 36a96121f4
commit a5db84bf35
9 changed files with 423 additions and 240 deletions

View File

@ -722,6 +722,7 @@ ecma_source = [
"ecmascript/async_generator_helper.cpp",
"ecmascript/global_env.cpp",
"ecmascript/global_env_constants.cpp",
"ecmascript/ic/ic_handler.cpp",
"ecmascript/ic/ic_runtime.cpp",
"ecmascript/ic/profile_type_info.cpp",
"ecmascript/ic/property_box.cpp",

View File

@ -34,6 +34,7 @@ namespace panda::ecmascript {
#define ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER 0
#define ECMASCRIPT_ENABLE_ELEMENTSKIND_ALWAY_GENERIC 0
#define ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT 0
#define ECMASCRIPT_ENABLE_TRACE_IC 0
#define ENABLE_NEXT_OPTIMIZATION 1

View 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

View File

@ -194,85 +194,15 @@ public:
{
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 {
public:
static inline JSHandle<JSTaggedValue> 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();
}
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 JSHandle<JSTaggedValue> LoadProperty(const JSThread *thread, const ObjectOperator &op);
static JSHandle<JSTaggedValue> LoadElement(const JSThread *thread, const ObjectOperator &op);
static inline JSHandle<JSTaggedValue> LoadStringElement(const JSThread *thread)
{
@ -293,45 +223,7 @@ public:
class StoreHandler final : public HandlerBase {
public:
static inline 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 JSHandle<JSTaggedValue> StoreProperty(const JSThread *thread, const ObjectOperator &op);
static inline JSHandle<JSTaggedValue> StoreElement(const JSThread *thread,
JSHandle<JSTaggedValue> receiver, uint64_t handler)
@ -364,16 +256,7 @@ public:
return static_cast<TransitionHandler *>(object);
}
static inline 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 JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op);
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
@ -391,68 +274,10 @@ public:
return static_cast<PrototypeHandler *>(object);
}
static inline JSHandle<JSTaggedValue> 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);
}
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 JSHandle<JSTaggedValue> LoadPrototype(const JSThread *thread, const ObjectOperator &op,
const JSHandle<JSHClass> &hclass);
static JSHandle<JSTaggedValue> StorePrototype(const JSThread *thread, const ObjectOperator &op,
const JSHandle<JSHClass> &hclass);
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
@ -474,19 +299,8 @@ public:
return static_cast<TransWithProtoHandler *>(object);
}
static inline JSHandle<JSTaggedValue> 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);
}
static JSHandle<JSTaggedValue> StoreTransition(const JSThread *thread, const ObjectOperator &op,
const JSHandle<JSHClass> &hclass);
static constexpr size_t HANDLER_INFO_OFFSET = TaggedObjectSize();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, TRANSITION_HCLASS_OFFSET)
@ -505,19 +319,6 @@ public:
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();
ACCESSORS(HandlerInfo, HANDLER_INFO_OFFSET, PROTO_CELL_OFFSET)
ACCESSORS(ProtoCell, PROTO_CELL_OFFSET, HOLDER_OFFSET)

View File

@ -15,13 +15,13 @@
#include "ecmascript/ic/ic_runtime.h"
#include "ecmascript/ic/ic_handler.h"
#include "ecmascript/dfx/stackinfo/js_stackinfo.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/interpreter/slow_runtime_stub.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/shared_objects/js_shared_array.h"
namespace panda::ecmascript {
#define TRACE_IC 0 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
void ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedValue> key,
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::RequireObjectCoercible(thread_, receiver, "Cannot load property of null or undefined");
@ -210,7 +191,7 @@ JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSH
icAccessor_.SetAsMega();
return result.GetTaggedValue();
}
TraceIC(receiver, key);
TraceIC(GetThread(), receiver, key);
// do not cache element
if (!op.IsFastMode()) {
icAccessor_.SetAsMega();
@ -261,7 +242,7 @@ JSTaggedValue LoadICRuntime::LoadMiss(JSHandle<JSTaggedValue> receiver, JSHandle
icAccessor_.SetAsMega();
return result.GetTaggedValue();
}
TraceIC(receiver, key);
TraceIC(GetThread(), receiver, key);
// do not cache element
if (!op.IsFastMode()) {
icAccessor_.SetAsMega();
@ -320,7 +301,7 @@ JSTaggedValue LoadICRuntime::LoadTypedArrayValueMiss(JSHandle<JSTaggedValue> rec
icAccessor_.SetAsMega();
return result.GetTaggedValue();
}
TraceIC(receiver, key);
TraceIC(GetThread(), receiver, key);
// do not cache element
if (!op.IsFastMode()) {
icAccessor_.SetAsMega();
@ -408,7 +389,7 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle<JSTaggedValue> receiver, JSHand
return JSTaggedValue::Undefined();
}
TraceIC(receiver, key);
TraceIC(GetThread(), receiver, key);
if (success) {
UpdateStoreHandler(op, key, receiver);
}
@ -474,7 +455,7 @@ JSTaggedValue StoreICRuntime::StoreTypedArrayValueMiss(JSHandle<JSTaggedValue> r
return JSTaggedValue::Undefined();
}
TraceIC(receiver, key);
TraceIC(GetThread(), receiver, key);
if (success) {
UpdateStoreHandler(op, key, receiver);
}
@ -494,4 +475,56 @@ JSTaggedValue StoreICRuntime::HandleAccesor(ObjectOperator *op, const JSHandle<J
}
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

View File

@ -57,7 +57,12 @@ public:
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:
JSThread *thread_;

View File

@ -223,6 +223,7 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::StoreICWithHandler(JSThread *thread, JST
INTERPRETER_TRACE(thread, StoreICWithHandler);
if (handler.IsInt()) {
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
if (HandlerBase::IsNonSharedStoreField(handlerInfo)) {
StoreField(thread, JSObject::Cast(receiver.GetTaggedObject()), value, handlerInfo);
return JSTaggedValue::Undefined();
@ -452,6 +453,7 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithHandler(JSThread *thread, JSTa
INTERPRETER_TRACE(thread, LoadICWithHandler);
if (LIKELY(handler.IsInt())) {
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
if (LIKELY(HandlerBase::IsField(handlerInfo))) {
return LoadFromField(JSObject::Cast(holder.GetTaggedObject()), handlerInfo);
}
@ -481,6 +483,7 @@ ARK_INLINE JSTaggedValue ICRuntimeStub::LoadICWithElementHandler(JSThread *threa
{
if (LIKELY(handler.IsInt())) {
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
HandlerBase::PrintLoadHandler(handlerInfo, std::cout);
if (HandlerBase::IsNormalElement(handlerInfo)) {
return LoadElement(JSObject::Cast(receiver.GetTaggedObject()), key);
} else if (HandlerBase::IsTypedArrayElement(handlerInfo)) {
@ -556,6 +559,7 @@ JSTaggedValue ICRuntimeStub::StoreElement(JSThread *thread, JSObject *receiver,
uint32_t elementIndex = static_cast<uint32_t>(index);
if (handler.IsInt()) {
auto handlerInfo = JSTaggedValue::UnwrapToUint64(handler);
HandlerBase::PrintStoreHandler(handlerInfo, std::cout);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSObject> receiverHandle(thread, receiver);
JSHandle<JSTaggedValue> valueHandle(thread, value);

View File

@ -476,6 +476,11 @@ public:
return kind_;
}
uint32_t GetSlotId() const
{
return slotId_;
}
private:
JSThread* thread_;
JSHandle<ProfileTypeInfo> profileTypeInfo_;

View File

@ -155,8 +155,8 @@ HWTEST_F_L0(ICRunTimeTest, TraceIC)
JSHandle<ProfileTypeInfo> handleProfileTypeInfo = factory->NewProfileTypeInfo(arrayLength);
ICRuntime icRuntime(thread, handleProfileTypeInfo, 4, ICKind::NamedGlobalLoadIC); // 4: means the NamedGlobalLoadIC
icRuntime.TraceIC(handleReceiver, handleKeyWithString);
icRuntime.TraceIC(handleReceiver, handleKeyWithElement);
icRuntime.TraceIC(thread, handleReceiver, handleKeyWithString);
icRuntime.TraceIC(thread, handleReceiver, handleKeyWithElement);
}
HWTEST_F_L0(ICRunTimeTest, StoreMiss)