Feat(Aot): PGO ArrayLiteral elemnetKind for array aot opt

Issue: #I7NYFW
Change-Id: I59ed5b9c377f2ce6bad2723795309099e015f8df
Signed-off-by: yingguofeng@huawei.com <yingguofeng@huawei.com>
This commit is contained in:
yingguofeng@huawei.com 2023-08-02 09:56:06 +08:00
parent bd56fe10ac
commit 169977e926
54 changed files with 860 additions and 169 deletions

View File

@ -604,6 +604,7 @@ ecma_source = [
"ecmascript/ecma_string.cpp",
"ecmascript/ecma_string_table.cpp",
"ecmascript/ecma_vm.cpp",
"ecmascript/elements.cpp",
"ecmascript/frames.cpp",
"ecmascript/free_object.cpp",
"ecmascript/generator_helper.cpp",

View File

@ -2069,13 +2069,15 @@ void Builtins::InitializeArray(const JSHandle<GlobalEnv> &env, const JSHandle<JS
// Array.prototype
JSHandle<JSObject> arrFuncPrototype = factory_->NewJSObjectWithInit(arrBaseFuncInstanceHClass);
JSHandle<JSArray>::Cast(arrFuncPrototype)->SetLength(thread_, JSTaggedValue(FunctionLength::ZERO));
JSHandle<JSArray>::Cast(arrFuncPrototype)->SetLength(FunctionLength::ZERO);
auto accessor = thread_->GlobalConstants()->GetArrayLengthAccessor();
JSArray::Cast(*arrFuncPrototype)->SetPropertyInlinedProps(thread_, JSArray::LENGTH_INLINE_PROPERTY_INDEX, accessor);
JSHandle<JSTaggedValue> arrFuncPrototypeValue(arrFuncPrototype);
// Array.prototype_or_hclass
JSHandle<JSHClass> arrFuncInstanceHClass = factory_->CreateJSArrayInstanceClass(arrFuncPrototypeValue);
auto globalConstant = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
globalConstant->InitElementKindHClass(thread_, arrFuncInstanceHClass);
// Array = new Function()
JSHandle<JSObject> arrayFunction(

View File

@ -165,6 +165,7 @@ GateRef AccessObjectStubBuilder::LoadObjByValue(GateRef glue, GateRef receiver,
{
result = CallRuntime(glue, RTSTUB_ID(LoadICByValue),
{ profileTypeInfo, receiver, key, IntToTaggedInt(slotId) });
callback.ProfileObjLayoutByLoad(receiver);
Jump(&exit);
}
Bind(&exit);
@ -225,6 +226,7 @@ GateRef AccessObjectStubBuilder::StoreObjByValue(GateRef glue, GateRef receiver,
{
result = CallRuntime(glue, RTSTUB_ID(StoreICByValue),
{ profileTypeInfo, receiver, key, value, IntToTaggedInt(slotId) });
callback.ProfileObjLayoutByStore(receiver);
Jump(&exit);
}
Bind(&exit);

View File

@ -467,6 +467,11 @@ namespace panda::ecmascript::kungfu {
APPEND_SUFFIX(HandleDefinegettersetterbyvalueV8V8V8V8, V) \
APPEND_SUFFIX(HandleCreateobjectwithbufferImm8Id16, V) \
APPEND_SUFFIX(HandleCreateobjectwithbufferImm16Id16, V) \
APPEND_SUFFIX(HandleCreatearraywithbufferImm8Id16, V) \
APPEND_SUFFIX(HandleCreatearraywithbufferImm16Id16, V) \
APPEND_SUFFIX(HandleCreateemptyobject, V) \
APPEND_SUFFIX(HandleCreateemptyarrayImm8, V) \
APPEND_SUFFIX(HandleCreateemptyarrayImm16, V) \
APPEND_SUFFIX(HandleLdobjbynameImm8Id16, V) \
APPEND_SUFFIX(HandleLdobjbynameImm16Id16, V) \
APPEND_SUFFIX(HandleLdthisbynameImm16Id16, V) \
@ -479,6 +484,19 @@ namespace panda::ecmascript::kungfu {
APPEND_SUFFIX(HandleStobjbynameImm8Id16V8, V) \
APPEND_SUFFIX(HandleStobjbynameImm16Id16V8, V) \
APPEND_SUFFIX(HandleStobjbyvalueImm8V8V8, V) \
APPEND_SUFFIX(HandleStobjbyindexImm8V8Imm16, V) \
APPEND_SUFFIX(HandleStobjbyindexImm16V8Imm16, V) \
APPEND_SUFFIX(HandleLdobjbyvalueImm8V8, V) \
APPEND_SUFFIX(HandleLdobjbyvalueImm16V8, V) \
APPEND_SUFFIX(HandleLdthisbyvalueImm16, V) \
APPEND_SUFFIX(HandleLdthisbyvalueImm8, V) \
APPEND_SUFFIX(HandleLdobjbyindexImm8Imm16, V) \
APPEND_SUFFIX(HandleLdobjbyindexImm16Imm16, V) \
APPEND_SUFFIX(HandleWideLdobjbyindexPrefImm32, V) \
APPEND_SUFFIX(HandleWideStobjbyindexPrefV8Imm32, V) \
APPEND_SUFFIX(HandleStownbyindexImm16V8Imm16, V) \
APPEND_SUFFIX(HandleStownbyindexImm8V8Imm16, V) \
APPEND_SUFFIX(HandleWideStownbyindexPrefV8Imm32, V) \
APPEND_SUFFIX(HandleStownbyvaluewithnamesetImm16V8V8, V) \
APPEND_SUFFIX(HandleStownbyvaluewithnamesetImm8V8V8, V) \
APPEND_SUFFIX(HandleStownbyvalueImm8V8V8, V) \

View File

@ -931,7 +931,7 @@ DECLARE_BUILTINS(FunctionPrototypeApply)
}
Bind(&taggedNotStableJsArg);
{
GateRef length = GetLengthOfJsArray(glue, arrayObj);
GateRef length = GetArrayLength(arrayObj);
GateRef argsLength = MakeArgListWithHole(glue, elements, length);
GateRef elementArgv = PtrAdd(elements, IntPtr(TaggedArray::DATA_OFFSET));
res = JSCallDispatch(glue, thisValue, argsLength, 0, Circuit::NullGate(),
@ -1165,7 +1165,7 @@ DECLARE_BUILTINS(ArrayConstructor)
newBuilder.SetParameters(glue, 0);
res = newBuilder.NewJSArrayWithSize(intialHClass, *arrayLength);
GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
Store(VariableType::JS_ANY(), glue, *res, lengthOffset, Int64ToTaggedInt(*arrayLength));
Store(VariableType::INT32(), glue, *res, lengthOffset, TruncInt64ToInt32(*arrayLength));
GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
ConstantIndex::ARRAY_LENGTH_ACCESSOR);
SetPropertyInlinedProps(glue, *res, intialHClass, accessor,
@ -1187,4 +1187,4 @@ DECLARE_BUILTINS(ArrayConstructor)
Bind(&exit);
Return(*res);
}
} // namespace panda::ecmascript::kungfu
} // namespace panda::ecmascript::kungfu

View File

@ -1458,7 +1458,7 @@ DEF_CALL_SIGNATURE(ProfileCreateObject)
VariableType::JS_ANY(),
VariableType::INT32(),
VariableType::JS_ANY(),
VariableType::JS_ANY(),
VariableType::INT32(),
};
callSign->SetVariadicArgs(true);
callSign->SetParameters(params.data());

View File

@ -409,6 +409,13 @@ GateRef CircuitBuilder::TaggedIsGeneratorObject(GateRef x)
return LogicAnd(isHeapObj, isAsyncGeneratorObj);
}
GateRef CircuitBuilder::TaggedIsJSArray(GateRef x)
{
GateRef objType = GetObjectType(LoadHClass(x));
GateRef isJSArray = Equal(objType, Int32(static_cast<int32_t>(JSType::JS_ARRAY)));
return isJSArray;
}
GateRef CircuitBuilder::TaggedIsPropertyBox(GateRef x)
{
return LogicAnd(TaggedIsHeapObject(x),

View File

@ -469,6 +469,7 @@ public:
inline GateRef TaggedIsAsyncGeneratorObject(GateRef x);
inline GateRef TaggedIsJSGlobalObject(GateRef x);
inline GateRef TaggedIsGeneratorObject(GateRef x);
inline GateRef TaggedIsJSArray(GateRef x);
inline GateRef TaggedIsPropertyBox(GateRef x);
inline GateRef TaggedIsWeak(GateRef x);
inline GateRef TaggedIsPrototypeHandler(GateRef x);

View File

@ -316,7 +316,7 @@ void SetPropertyByIndexStubBuilder::GenerateCircuit()
GateRef receiver = TaggedArgument(1);
GateRef index = Int32Argument(2); /* 2 : 3rd parameter is index */
GateRef value = TaggedArgument(3); /* 3 : 4th parameter is value */
Return(SetPropertyByIndex(glue, receiver, index, value, false));
Return(SetPropertyByIndex(glue, receiver, index, value, false, ProfileOperation()));
}
void SetPropertyByIndexWithOwnStubBuilder::GenerateCircuit()
@ -325,7 +325,7 @@ void SetPropertyByIndexWithOwnStubBuilder::GenerateCircuit()
GateRef receiver = TaggedArgument(1);
GateRef index = Int32Argument(2); /* 2 : 3rd parameter is index */
GateRef value = TaggedArgument(3); /* 3 : 4th parameter is value */
Return(SetPropertyByIndex(glue, receiver, index, value, true));
Return(SetPropertyByIndex(glue, receiver, index, value, true, ProfileOperation()));
}
void GetPropertyByNameStubBuilder::GenerateCircuit()
@ -546,7 +546,7 @@ void TryLoadICByValueStubBuilder::GenerateCircuit()
&hclassEqualFirstValue,
&hclassNotEqualFirstValue);
Bind(&hclassEqualFirstValue);
Return(LoadElement(glue, receiver, key));
Return(LoadElement(glue, receiver, key, ProfileOperation()));
Bind(&hclassNotEqualFirstValue);
{
Branch(Int64Equal(firstValue, key), &firstValueEqualKey, &receiverNotHeapObject);
@ -624,7 +624,7 @@ void TryStoreICByValueStubBuilder::GenerateCircuit()
&hclassEqualFirstValue,
&hclassNotEqualFirstValue);
Bind(&hclassEqualFirstValue);
Return(ICStoreElement(glue, receiver, key, value, secondValue));
Return(ICStoreElement(glue, receiver, key, value, secondValue, ProfileOperation()));
Bind(&hclassNotEqualFirstValue);
{
Branch(Int64Equal(firstValue, key), &firstValueEqualKey, &receiverNotHeapObject);
@ -672,7 +672,7 @@ void CreateEmptyArrayStubBuilder::GenerateCircuit()
{
GateRef glue = PtrArgument(0);
NewObjectStubBuilder newBuilder(this);
Return(newBuilder.CreateEmptyArray(glue));
Return(newBuilder.CreateEmptyArray(glue, ProfileOperation()));
}
void CreateArrayWithBufferStubBuilder::GenerateCircuit()
@ -681,7 +681,7 @@ void CreateArrayWithBufferStubBuilder::GenerateCircuit()
GateRef index = Int32Argument(1);
GateRef jsFunc = TaggedArgument(2); // 2 : 3rd para
NewObjectStubBuilder newBuilder(this);
Return(newBuilder.CreateArrayWithBuffer(glue, index, jsFunc));
Return(newBuilder.CreateArrayWithBuffer(glue, index, jsFunc, ProfileOperation()));
}
void NewJSObjectStubBuilder::GenerateCircuit()

View File

@ -147,7 +147,7 @@ void ICStubBuilder::LoadICByValue(
ValuedICAccessor(&cachedHandler, &loadWithHandler, &loadElement);
Bind(&loadElement);
{
GateRef ret = LoadElement(glue_, receiver_, propKey_);
GateRef ret = LoadElement(glue_, receiver_, propKey_, callback);
result->WriteVariable(ret);
Branch(TaggedIsHole(ret), slowPath_, success_);
}
@ -172,7 +172,7 @@ void ICStubBuilder::StoreICByValue(Variable* result, Label* tryFastPath, Label *
ValuedICAccessor(&cachedHandler, &storeWithHandler, &storeElement);
Bind(&storeElement);
{
GateRef ret = ICStoreElement(glue_, receiver_, propKey_, value_, secondValue);
GateRef ret = ICStoreElement(glue_, receiver_, propKey_, value_, secondValue, callback_);
result->WriteVariable(ret);
Branch(TaggedIsHole(ret), slowPath_, success_);
}

View File

@ -427,6 +427,7 @@ DECLARE_ASM_HANDLER(HandleCreateemptyobject)
{
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
GateRef res = CallRuntime(glue, RTSTUB_ID(CreateEmptyObject), {});
callback.ProfileCreateObject(res);
varAcc = res;
DISPATCH_WITH_ACC(CREATEEMPTYOBJECT);
}
@ -435,7 +436,7 @@ DECLARE_ASM_HANDLER(HandleCreateemptyarrayImm8)
{
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
NewObjectStubBuilder newBuilder(this);
varAcc = newBuilder.CreateEmptyArray(glue);
varAcc = newBuilder.CreateEmptyArray(glue, callback);
DISPATCH_WITH_ACC(CREATEEMPTYARRAY_IMM8);
}
@ -443,7 +444,7 @@ DECLARE_ASM_HANDLER(HandleCreateemptyarrayImm16)
{
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
NewObjectStubBuilder newBuilder(this);
varAcc = newBuilder.CreateEmptyArray(glue);
varAcc = newBuilder.CreateEmptyArray(glue, callback);
DISPATCH_WITH_ACC(CREATEEMPTYARRAY_IMM16);
}
@ -1470,7 +1471,7 @@ DECLARE_ASM_HANDLER(HandleStobjbyindexImm8V8Imm16)
Branch(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
Bind(&fastPath);
{
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, false);
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, false, callback);
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
@ -1496,7 +1497,7 @@ DECLARE_ASM_HANDLER(HandleStobjbyindexImm16V8Imm16)
Branch(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
Bind(&fastPath);
{
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, false);
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, false, callback);
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
@ -1521,7 +1522,7 @@ DECLARE_ASM_HANDLER(HandleWideStobjbyindexPrefV8Imm32)
Branch(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
Bind(&fastPath);
{
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, false);
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, false, callback);
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
@ -1554,7 +1555,7 @@ DECLARE_ASM_HANDLER(HandleStownbyindexImm16V8Imm16)
Bind(&notClassPrototype);
{
// fast path
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true); // acc is value
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true, callback); // acc is value
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
@ -1587,7 +1588,7 @@ DECLARE_ASM_HANDLER(HandleStownbyindexImm8V8Imm16)
Bind(&notClassPrototype);
{
// fast path
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true); // acc is value
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true, callback); // acc is value
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
@ -1619,7 +1620,7 @@ DECLARE_ASM_HANDLER(HandleWideStownbyindexPrefV8Imm32)
Bind(&notClassPrototype);
{
// fast path
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true); // acc is value
GateRef result = SetPropertyByIndex(glue, receiver, index, acc, true, callback); // acc is value
Label notHole(env);
Branch(TaggedIsHole(result), &slowPath, &notHole);
Bind(&notHole);
@ -3821,7 +3822,7 @@ DECLARE_ASM_HANDLER(HandleCreatearraywithbufferImm8Id16)
GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
NewObjectStubBuilder newBuilder(this);
GateRef res = newBuilder.CreateArrayWithBuffer(glue, imm, currentFunc);
GateRef res = newBuilder.CreateArrayWithBuffer(glue, imm, currentFunc, callback);
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEARRAYWITHBUFFER_IMM8_ID16));
}
@ -3831,7 +3832,7 @@ DECLARE_ASM_HANDLER(HandleCreatearraywithbufferImm16Id16)
GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
NewObjectStubBuilder newBuilder(this);
GateRef res = newBuilder.CreateArrayWithBuffer(glue, imm, currentFunc);
GateRef res = newBuilder.CreateArrayWithBuffer(glue, imm, currentFunc, callback);
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEARRAYWITHBUFFER_IMM16_ID16));
}
@ -3841,7 +3842,7 @@ DECLARE_ASM_HANDLER(HandleDeprecatedCreatearraywithbufferPrefImm16)
GateRef currentFunc = GetFunctionFromFrame(GetFrame(sp));
NewObjectStubBuilder newBuilder(this);
GateRef res = newBuilder.CreateArrayWithBuffer(glue, imm, currentFunc);
GateRef res = newBuilder.CreateArrayWithBuffer(glue, imm, currentFunc, callback);
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(DEPRECATED_CREATEARRAYWITHBUFFER_PREF_IMM16));
}
@ -3853,7 +3854,7 @@ DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm8Id16)
GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module);
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
callback.ProfileCreateObject(result, res);
callback.ProfileCreateObject(res);
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM8_ID16));
}
@ -3865,7 +3866,7 @@ DECLARE_ASM_HANDLER(HandleCreateobjectwithbufferImm16Id16)
GateRef result = GetObjectLiteralFromConstPool(glue, constpool, imm, module);
GateRef currentEnv = GetEnvFromFrame(GetFrame(sp));
GateRef res = CallRuntime(glue, RTSTUB_ID(CreateObjectHavingMethod), { result, currentEnv });
callback.ProfileCreateObject(result, res);
callback.ProfileCreateObject(res);
CHECK_EXCEPTION_WITH_ACC(res, INT_PTR(CREATEOBJECTWITHBUFFER_IMM16_ID16));
}

View File

@ -289,7 +289,7 @@ void NewObjectStubBuilder::NewJSArrayLiteral(Variable *result, Label *exit, Regi
if (isEmptyArray) {
Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), propertiesOffset, obj);
Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), elementsOffset, obj);
Store(VariableType::JS_ANY(), glue_, result->ReadVariable(), lengthOffset, IntToTaggedInt(Int32(0)));
Store(VariableType::INT32(), glue_, result->ReadVariable(), lengthOffset, Int32(0));
} else {
auto newProperties = Load(VariableType::JS_POINTER(), obj, propertiesOffset);
Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), propertiesOffset, newProperties);
@ -297,8 +297,8 @@ void NewObjectStubBuilder::NewJSArrayLiteral(Variable *result, Label *exit, Regi
auto newElements = Load(VariableType::JS_POINTER(), obj, elementsOffset);
Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), elementsOffset, newElements);
GateRef arrayLength = Load(VariableType::JS_ANY(), obj, lengthOffset);
Store(VariableType::JS_ANY(), glue_, result->ReadVariable(), lengthOffset, arrayLength);
GateRef arrayLength = Load(VariableType::INT32(), obj, lengthOffset);
Store(VariableType::INT32(), glue_, result->ReadVariable(), lengthOffset, arrayLength);
}
auto accessor = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::ARRAY_LENGTH_ACCESSOR);
@ -499,7 +499,7 @@ GateRef NewObjectStubBuilder::NewThisObjectChecked(GateRef glue, GateRef ctor)
return ret;
}
GateRef NewObjectStubBuilder::CreateEmptyArray(GateRef glue)
GateRef NewObjectStubBuilder::CreateEmptyArray(GateRef glue, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
@ -517,14 +517,20 @@ GateRef NewObjectStubBuilder::CreateEmptyArray(GateRef glue)
SetParameters(glue, size);
NewJSArrayLiteral(&result, &exit, RegionSpaceFlag::IN_YOUNG_SPACE, emptyArray, hclass, true);
Bind(&exit);
auto ret = *result;
if (!callback.IsEmpty()) {
auto noneHClass =
GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::ELEMENT_NONE_HCLASS_INDEX);
StoreHClass(glue, ret, noneHClass);
callback.ProfileCreateObject(ret);
}
env->SubCfgExit();
return ret;
}
GateRef NewObjectStubBuilder::CreateArrayWithBuffer(GateRef glue, GateRef index, GateRef jsFunc)
GateRef NewObjectStubBuilder::CreateArrayWithBuffer(
GateRef glue, GateRef index, GateRef jsFunc, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
@ -545,6 +551,7 @@ GateRef NewObjectStubBuilder::CreateArrayWithBuffer(GateRef glue, GateRef index,
Bind(&exit);
auto ret = *result;
callback.ProfileCreateObject(ret);
env->SubCfgExit();
return ret;
}

View File

@ -16,6 +16,7 @@
#ifndef ECMASCRIPT_COMPILER_NEW_OBJECT_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_NEW_OBJECT_STUB_BUILDER_H
#include "ecmascript/compiler/profiler_operation.h"
#include "ecmascript/compiler/stub_builder.h"
namespace panda::ecmascript::kungfu {
@ -56,8 +57,8 @@ public:
void InitializeWithSpeicalValue(Label *exit, GateRef object, GateRef value, GateRef start, GateRef end);
GateRef FastNewThisObject(GateRef glue, GateRef ctor);
GateRef NewThisObjectChecked(GateRef glue, GateRef ctor);
GateRef CreateEmptyArray(GateRef glue);
GateRef CreateArrayWithBuffer(GateRef glue, GateRef index, GateRef jsFunc);
GateRef CreateEmptyArray(GateRef glue, ProfileOperation callback);
GateRef CreateArrayWithBuffer(GateRef glue, GateRef index, GateRef jsFunc, ProfileOperation callback);
void NewTaggedArrayChecked(Variable *result, GateRef len, Label *exit);
private:

View File

@ -147,7 +147,7 @@ GateRef NTypeMCRLowering::NewJSArrayLiteral(GateRef elements, GateRef length)
builder_.Int64(JSTaggedValue(0).GetRawData()));
builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::PROPERTIES_OFFSET, emptyArray);
builder_.StoreConstOffset(VariableType::JS_POINTER(), array, JSObject::ELEMENTS_OFFSET, elements);
builder_.StoreConstOffset(VariableType::JS_ANY(), array, JSArray::LENGTH_OFFSET, builder_.Int32ToTaggedInt(length));
builder_.StoreConstOffset(VariableType::INT32(), array, JSArray::LENGTH_OFFSET, length);
builder_.StoreConstOffset(VariableType::JS_POINTER(), array, lengthAccessorOffset, accessor);
builder_.FinishAllocate();
return array;

View File

@ -76,10 +76,10 @@ public:
}
}
inline void ProfileCreateObject(GateRef originObj, GateRef newObj) const
inline void ProfileCreateObject(GateRef newObj) const
{
if (callback_) {
callback_({ originObj, newObj }, OperationType::CREATE_OBJECT);
callback_({ newObj }, OperationType::CREATE_OBJECT);
}
}

View File

@ -34,7 +34,7 @@ void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, Ga
ProfileDefineClass(glue, pc, func, values[0]);
break;
case OperationType::CREATE_OBJECT:
ProfileCreateObject(glue, pc, func, values[0], values[1]);
ProfileCreateObject(glue, pc, func, values[0]);
break;
case OperationType::STORE_LAYOUT:
ProfileObjLayout(glue, pc, func, values[0], Int32(1));
@ -121,18 +121,48 @@ void ProfilerStubBuilder::ProfileDefineClass(GateRef glue, GateRef pc, GateRef f
env->SubCfgExit();
}
void ProfilerStubBuilder::ProfileCreateObject(GateRef glue, GateRef pc, GateRef func, GateRef originObj, GateRef newObj)
void ProfilerStubBuilder::ProfileCreateObject(GateRef glue, GateRef pc, GateRef func, GateRef newObj)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
GateRef firstPC =
Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
CallNGCRuntime(glue, RTSTUB_ID(ProfileCreateObject), { glue, func, offset, originObj, newObj });
DEFVARIABLE(traceId, VariableType::INT32(), Int32(0));
Label isArray(env);
Label profile(env);
Label calculateTraceId(env);
Branch(TaggedIsJSArray(newObj), &isArray, &calculateTraceId);
Bind(&isArray);
{
GateRef traceIdOffset = IntPtr(JSArray::TRACE_INDEX_OFFSET);
traceId = Load(VariableType::INT32(), newObj, traceIdOffset);
Label uninitialize(env);
Branch(Int32GreaterThan(*traceId, Int32(0)), &exit, &uninitialize);
Bind(&uninitialize);
{
auto pfAddr = LoadPfHeaderFromConstPool(func);
traceId = TruncPtrToInt32(PtrSub(pc, pfAddr));
Store(VariableType::INT32(), glue, newObj, traceIdOffset, *traceId);
Jump(&profile);
}
}
Bind(&calculateTraceId);
{
auto pfAddr = LoadPfHeaderFromConstPool(func);
traceId = TruncPtrToInt32(PtrSub(pc, pfAddr));
Jump(&profile);
}
Bind(&profile);
{
GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
GateRef firstPC =
Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
CallNGCRuntime(glue, RTSTUB_ID(ProfileCreateObject), { glue, func, offset, newObj, *traceId });
Jump(&exit);
}
Bind(&exit);
env->SubCfgExit();
}

View File

@ -34,7 +34,7 @@ public:
void ProfileCall(GateRef glue, GateRef pc, GateRef func, GateRef target);
void ProfileOpType(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, GateRef type);
void ProfileDefineClass(GateRef glue, GateRef pc, GateRef func, GateRef constructor);
void ProfileCreateObject(GateRef glue, GateRef pc, GateRef func, GateRef originObj, GateRef newObj);
void ProfileCreateObject(GateRef glue, GateRef pc, GateRef func, GateRef newObj);
void ProfileObjLayout(GateRef glue, GateRef pc, GateRef func, GateRef object, GateRef store);
GateRef UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback);

View File

@ -32,6 +32,7 @@
#include "ecmascript/js_generator_object.h"
#include "ecmascript/js_object.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/layout_info.h"
#include "ecmascript/message_string.h"
#include "ecmascript/mem/slots.h"
@ -634,6 +635,11 @@ inline GateRef StubBuilder::TaggedIsGeneratorObject(GateRef x)
return env_->GetBuilder()->TaggedIsGeneratorObject(x);
}
inline GateRef StubBuilder::TaggedIsJSArray(GateRef x)
{
return env_->GetBuilder()->TaggedIsJSArray(x);
}
inline GateRef StubBuilder::TaggedIsAsyncGeneratorObject(GateRef x)
{
return env_->GetBuilder()->TaggedIsAsyncGeneratorObject(x);
@ -1663,6 +1669,14 @@ inline GateRef StubBuilder::GetInlinedPropertiesFromHClass(GateRef hClass)
return Int32Sub(objectSizeInWords, inlinedPropsStart);
}
inline GateRef StubBuilder::GetElementsKindFromHClass(GateRef hClass)
{
GateRef bitfield = Load(VariableType::INT32(), hClass, IntPtr(JSHClass::BIT_FIELD_OFFSET));
return Int32And(Int32LSR(bitfield,
Int32(JSHClass::ElementsKindBits::START_BIT)),
Int32((1LLU << JSHClass::ElementsKindBits::SIZE) - 1));
}
inline GateRef StubBuilder::GetObjectSizeFromHClass(GateRef hClass)
{
return env_->GetBuilder()->GetObjectSizeFromHClass(hClass);
@ -2420,5 +2434,18 @@ inline GateRef StubBuilder::LoadObjectFromConstPool(GateRef jsFunc, GateRef inde
{
return env_->GetBuilder()->LoadObjectFromConstPool(jsFunc, index);
}
inline GateRef StubBuilder::LoadPfHeaderFromConstPool(GateRef jsFunc)
{
GateRef method = Load(VariableType::JS_ANY(), jsFunc, IntPtr(JSFunctionBase::METHOD_OFFSET));
GateRef constPool = Load(VariableType::JS_ANY(), method, IntPtr(Method::CONSTANT_POOL_OFFSET));
auto length = GetLengthOfTaggedArray(constPool);
auto index = Int32Sub(length, Int32(ConstantPool::JS_PANDA_FILE_INDEX));
auto jsPandaFile = GetValueFromTaggedArray(constPool, index);
auto jsPfAddr = ChangeInt64ToIntPtr(ChangeTaggedPointerToInt64(jsPandaFile));
auto pfAddr = Load(VariableType::NATIVE_POINTER(), jsPfAddr, Int32(JSPandaFile::PF_OFFSET));
auto pfHeader = Load(VariableType::NATIVE_POINTER(), pfAddr, Int32(0));
return pfHeader;
}
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_STUB_INL_H

View File

@ -581,8 +581,7 @@ GateRef StubBuilder::CallGetterHelper(
Branch(Equal(accessor, lengthAccessor), &arrayLength, &tryContinue);
Bind(&arrayLength);
{
result = Load(VariableType::JS_ANY(), holder,
IntPtr(JSArray::LENGTH_OFFSET));
result = IntToTaggedPtr(Load(VariableType::INT32(), holder, IntPtr(JSArray::LENGTH_OFFSET)));
Jump(&exit);
}
Bind(&tryContinue);
@ -941,6 +940,60 @@ GateRef StubBuilder::TaggedToRepresentation(GateRef value)
return ret;
}
GateRef StubBuilder::TaggedToElementKind(GateRef value)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
DEFVARIABLE(result, VariableType::INT32(), Int32(static_cast<int32_t>(ElementsKind::TAGGED)));
Label isInt(env);
Label isNotInt(env);
Branch(TaggedIsInt(value), &isInt, &isNotInt);
Bind(&isInt);
{
result = Int32(static_cast<int32_t>(ElementsKind::INT));
Jump(&exit);
}
Bind(&isNotInt);
{
Label isObject(env);
Label isDouble(env);
Branch(TaggedIsObject(value), &isObject, &isDouble);
Bind(&isDouble);
{
result = Int32(static_cast<int32_t>(ElementsKind::DOUBLE));
Jump(&exit);
}
Bind(&isObject);
{
Label isHeapObject(env);
Branch(TaggedIsHeapObject(value), &isHeapObject, &exit);
Bind(&isHeapObject);
{
Label isString(env);
Label isNonString(env);
Branch(TaggedIsString(value), &isString, &isNonString);
Bind(&isString);
{
result = Int32(static_cast<int32_t>(ElementsKind::STRING));
Jump(&exit);
}
Bind(&isNonString);
{
result = Int32(static_cast<int32_t>(ElementsKind::OBJECT));
Jump(&exit);
}
}
}
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
void StubBuilder::Store(VariableType type, GateRef glue, GateRef base, GateRef offset, GateRef value)
{
if (!env_->IsAsmInterp()) {
@ -1584,7 +1637,7 @@ GateRef StubBuilder::LoadICWithHandler(
return ret;
}
GateRef StubBuilder::LoadElement(GateRef glue, GateRef receiver, GateRef key)
GateRef StubBuilder::LoadElement(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
@ -1609,6 +1662,7 @@ GateRef StubBuilder::LoadElement(GateRef glue, GateRef receiver, GateRef key)
Jump(&exit);
Bind(&lengthNotLessIndex);
result = GetValueFromTaggedArray(elements, index);
callback.ProfileObjLayoutByLoad(receiver);
Jump(&exit);
}
Bind(&exit);
@ -1617,7 +1671,8 @@ GateRef StubBuilder::LoadElement(GateRef glue, GateRef receiver, GateRef key)
return ret;
}
GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef handler)
GateRef StubBuilder::ICStoreElement(
GateRef glue, GateRef receiver, GateRef key, GateRef value, GateRef handler, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
@ -1674,9 +1729,9 @@ GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key,
GateRef oldLength = GetArrayLength(receiver);
Branch(Int32GreaterThanOrEqual(index, oldLength), &indexGreaterLength, &handerInfoNotJSArray);
Bind(&indexGreaterLength);
Store(VariableType::INT64(), glue, receiver,
Store(VariableType::INT32(), glue, receiver,
IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET),
IntToTaggedInt(Int32Add(index, Int32(1))));
Int32Add(index, Int32(1)));
}
Jump(&handerInfoNotJSArray);
}
@ -1691,11 +1746,33 @@ GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key,
RTSTUB_ID(TaggedArraySetValue),
{ receiver, value, elements, IntToTaggedInt(index),
IntToTaggedInt(capacity) });
Jump(&exit);
Label transition(env);
Branch(TaggedIsHole(*result), &exit, &transition);
Bind(&transition);
{
Label hole(env);
Label notHole(env);
DEFVARIABLE(kind, VariableType::INT32(), Int32(static_cast<int32_t>(ElementsKind::NONE)));
Branch(Int32GreaterThan(index, capacity), &hole, &notHole);
Bind(&hole);
{
kind = Int32(static_cast<int32_t>(ElementsKind::HOLE));
Jump(&notHole);
}
Bind(&notHole);
{
TransitToElementsKind(glue, receiver, value, *kind);
callback.ProfileObjLayoutByStore(receiver);
Jump(&exit);
}
}
}
Bind(&storeElement);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, value);
TransitToElementsKind(
glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
callback.ProfileObjLayoutByStore(receiver);
result = Undefined();
Jump(&exit);
}
@ -1724,30 +1801,9 @@ GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key,
GateRef StubBuilder::GetArrayLength(GateRef object)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
Label lengthIsInt(env);
Label lengthNotInt(env);
DEFVARIABLE(result, VariableType::INT32(), Int32(0));
GateRef lengthOffset = IntPtr(panda::ecmascript::JSArray::LENGTH_OFFSET);
GateRef length = Load(VariableType::INT64(), object, lengthOffset);
Branch(TaggedIsInt(length), &lengthIsInt, &lengthNotInt);
Bind(&lengthIsInt);
{
result = GetInt32OfTInt(length);
Jump(&exit);
}
Bind(&lengthNotInt);
{
result = ChangeFloat64ToInt32(GetDoubleOfTDouble(length));
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
GateRef result = Load(VariableType::INT32(), object, lengthOffset);
return result;
}
GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef argHolder,
@ -2171,6 +2227,7 @@ GateRef StubBuilder::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef
Label notHole(env);
Label isHole(env);
GateRef value = GetValueFromTaggedArray(elements, index);
callback.ProfileObjLayoutByLoad(receiver);
Branch(TaggedIsNotHole(value), &notHole, &isHole);
Bind(&notHole);
{
@ -2503,6 +2560,36 @@ void StubBuilder::TransitionForRepChange(GateRef glue, GateRef receiver, GateRef
env->SubCfgExit();
}
void StubBuilder::TransitToElementsKind(GateRef glue, GateRef receiver, GateRef value, GateRef kind)
{
auto env = GetEnvironment();
Label subEntry(env);
env->SubCfgEntry(&subEntry);
Label exit(env);
GateRef hclass = LoadHClass(receiver);
GateRef elementsKind = GetElementsKindFromHClass(hclass);
Label isNoneDefault(env);
Branch(Int32Equal(elementsKind, Int32(static_cast<int32_t>(ElementsKind::GENERIC))), &exit, &isNoneDefault);
Bind(&isNoneDefault);
{
GateRef newKind = TaggedToElementKind(value);
newKind = Int32Or(newKind, kind);
newKind = Int32Or(newKind, elementsKind);
Label change(env);
Branch(Int32Equal(elementsKind, newKind), &exit, &change);
Bind(&change);
{
CallRuntime(glue, RTSTUB_ID(UpdateHClassForElementsKind), { receiver, newKind });
Jump(&exit);
}
}
Bind(&exit);
env->SubCfgExit();
}
GateRef StubBuilder::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, GateRef key, GateRef metaData)
{
auto env = GetEnvironment();
@ -2590,7 +2677,8 @@ GateRef StubBuilder::FindTransitions(GateRef glue, GateRef receiver, GateRef hcl
return ret;
}
GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn)
GateRef StubBuilder::SetPropertyByIndex(
GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn, ProfileOperation callback)
{
auto env = GetEnvironment();
Label entry(env);
@ -2675,6 +2763,9 @@ GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef
{
GateRef newElements = CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), {*holder});
SetValueToTaggedArray(VariableType::JS_ANY(), glue, newElements, index, value);
TransitToElementsKind(
glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
callback.ProfileObjLayoutByStore(receiver);
returnValue = Undefined();
Jump(&exit);
}
@ -2685,6 +2776,9 @@ GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef
Bind(&setElementsArray);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, value);
TransitToElementsKind(
glue, receiver, value, Int32(static_cast<int32_t>(ElementsKind::NONE)));
callback.ProfileObjLayoutByStore(receiver);
returnValue = Undefined();
Jump(&exit);
}
@ -2723,6 +2817,7 @@ GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef
Branch(TaggedIsTrue(result), &success, &failed);
Bind(&success);
{
callback.ProfileObjLayoutByStore(receiver);
returnValue = Undefined();
Jump(&exit);
}
@ -3067,7 +3162,7 @@ GateRef StubBuilder::SetPropertyByValue(GateRef glue, GateRef receiver, GateRef
Branch(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, &notValidIndex);
Bind(&validIndex);
{
result = SetPropertyByIndex(glue, receiver, index, value, useOwn);
result = SetPropertyByIndex(glue, receiver, index, value, useOwn, callback);
Jump(&exit);
}
Bind(&notValidIndex);

View File

@ -209,6 +209,7 @@ public:
GateRef ObjectAddressToRange(GateRef x);
GateRef InYoungGeneration(GateRef region);
GateRef TaggedIsGeneratorObject(GateRef x);
GateRef TaggedIsJSArray(GateRef x);
GateRef TaggedIsAsyncGeneratorObject(GateRef x);
GateRef TaggedIsJSGlobalObject(GateRef x);
GateRef TaggedIsWeak(GateRef x);
@ -406,6 +407,7 @@ public:
GateRef GetNumberOfPropsFromHClass(GateRef hClass);
GateRef IsTSHClass(GateRef hClass);
void SetNumberOfPropsToHClass(GateRef glue, GateRef hClass, GateRef value);
GateRef GetElementsKindFromHClass(GateRef hClass);
GateRef GetObjectSizeFromHClass(GateRef hClass);
GateRef GetInlinedPropsStartFromHClass(GateRef hClass);
GateRef GetInlinedPropertiesFromHClass(GateRef hClass);
@ -452,11 +454,13 @@ public:
GateRef ComputePropertyCapacityInJSObj(GateRef oldLength);
GateRef FindTransitions(GateRef glue, GateRef receiver, GateRef hClass, GateRef key, GateRef attr);
void TransitionForRepChange(GateRef glue, GateRef receiver, GateRef key, GateRef attr);
void TransitToElementsKind(GateRef glue, GateRef receiver, GateRef value, GateRef kind);
GateRef TaggedToRepresentation(GateRef value);
GateRef TaggedToElementKind(GateRef value);
GateRef LdGlobalRecord(GateRef glue, GateRef key);
GateRef LoadFromField(GateRef receiver, GateRef handlerInfo);
GateRef LoadGlobal(GateRef cell);
GateRef LoadElement(GateRef glue, GateRef receiver, GateRef key);
GateRef LoadElement(GateRef glue, GateRef receiver, GateRef key, ProfileOperation callback);
GateRef TryToElementsIndex(GateRef glue, GateRef key);
GateRef CheckPolyHClass(GateRef cachedValue, GateRef hClass);
GateRef LoadICWithHandler(
@ -464,7 +468,7 @@ public:
GateRef StoreICWithHandler(GateRef glue, GateRef receiver, GateRef holder,
GateRef value, GateRef handler, ProfileOperation callback = ProfileOperation());
GateRef ICStoreElement(GateRef glue, GateRef receiver, GateRef key,
GateRef value, GateRef handlerInfo);
GateRef value, GateRef handlerInfo, ProfileOperation callback);
GateRef GetArrayLength(GateRef object);
GateRef DoubleToInt(GateRef glue, GateRef x);
GateRef StoreField(GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback);
@ -535,7 +539,8 @@ public:
GateRef FastGetPropertyByName(GateRef glue, GateRef obj, GateRef key, ProfileOperation callback);
GateRef FastGetPropertyByIndex(GateRef glue, GateRef obj, GateRef index, ProfileOperation callback);
GateRef GetPropertyByValue(GateRef glue, GateRef receiver, GateRef keyValue, ProfileOperation callback);
GateRef SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn);
GateRef SetPropertyByIndex(
GateRef glue, GateRef receiver, GateRef index, GateRef value, bool useOwn, ProfileOperation callback);
GateRef SetPropertyByName(GateRef glue, GateRef receiver, GateRef key,
GateRef value, bool useOwn, ProfileOperation callback = ProfileOperation()); // Crawl prototype chain
GateRef SetPropertyByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value, bool useOwn,
@ -643,6 +648,7 @@ public:
void Comment(GateRef glue, const std::string &str);
GateRef ToNumber(GateRef glue, GateRef tagged);
inline GateRef LoadObjectFromConstPool(GateRef jsFunc, GateRef index);
inline GateRef LoadPfHeaderFromConstPool(GateRef jsFunc);
private:
using BinaryOperation = std::function<GateRef(Environment*, GateRef, GateRef)>;
GateRef ChangeTaggedPointerToInt64(GateRef x);

View File

@ -684,7 +684,7 @@ JSTaggedValue ContainersVector::CopyToArray(EcmaRuntimeCallInfo *argv)
JSHandle<TaggedArray> newArrayElement = factory->NewAndCopyTaggedArray(vectorElements,
vectorLength, vectorLength);
array->SetElements(thread, newArrayElement);
array->SetLength(thread, JSTaggedValue(vectorLength));
array->SetLength(vectorLength);
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return JSTaggedValue::True();

View File

@ -300,7 +300,7 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
case JSType::JS_ARRAY: {
JSArray *jsArray = JSArray::Cast(entry);
CString jsArrayName("JSArray[");
jsArrayName.append(ToCString(jsArray->GetLength().GetInt()));
jsArrayName.append(ToCString(jsArray->GetLength()));
jsArrayName.append("]");
return GetString(jsArrayName);
}

View File

@ -584,7 +584,7 @@ static void DumpHClass(const JSHClass *jshclass, std::ostream &os, bool withDeta
os << "IsCtor :" << std::boolalpha << jshclass->IsConstructor();
os << "| IsCallable :" << std::boolalpha << jshclass->IsCallable();
os << "| IsExtensible :" << std::boolalpha << jshclass->IsExtensible();
os << "| ElementRepresentation :" << static_cast<int>(jshclass->GetElementRepresentation());
os << "| ElementsKind :" << Elements::GetString(jshclass->GetElementsKind());
os << "| NumberOfProps :" << std::dec << jshclass->NumberOfProps();
os << "| InlinedProperties :" << std::dec << jshclass->GetInlinedProperties();
os << "| IsTS :" << std::boolalpha << jshclass->IsTS();

View File

@ -89,6 +89,8 @@ bool EcmaContext::Initialize()
JSType::GLOBAL_ENV);
thread_->SetGlobalConst(&globalConst_);
globalConst_.Init(thread_, *hClassHandle);
auto arrayHClassIndexMaps = Elements::InitializeHClassMap();
thread_->SetArrayHClassIndexMap(arrayHClassIndexMaps);
JSHandle<GlobalEnv> globalEnv = factory_->NewGlobalEnv(*globalEnvClass);
globalEnv->Init(thread_);

104
ecmascript/elements.cpp Normal file
View File

@ -0,0 +1,104 @@
/*
* 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.
*/
#include "ecmascript/elements.h"
#include "ecmascript/global_env_constants.h"
#include "ecmascript/js_tagged_value-inl.h"
namespace panda::ecmascript {
CMap<ElementsKind, ConstantIndex> Elements::InitializeHClassMap()
{
CMap<ElementsKind, ConstantIndex> result;
result.emplace(ElementsKind::NONE, ConstantIndex::ELEMENT_NONE_HCLASS_INDEX);
result.emplace(ElementsKind::INT, ConstantIndex::ELEMENT_INT_HCLASS_INDEX);
result.emplace(ElementsKind::DOUBLE, ConstantIndex::ELEMENT_DOUBLE_HCLASS_INDEX);
result.emplace(ElementsKind::NUMBER, ConstantIndex::ELEMENT_NUMBER_HCLASS_INDEX);
result.emplace(ElementsKind::STRING, ConstantIndex::ELEMENT_STRING_HCLASS_INDEX);
result.emplace(ElementsKind::OBJECT, ConstantIndex::ELEMENT_OBJECT_HCLASS_INDEX);
result.emplace(ElementsKind::TAGGED, ConstantIndex::ELEMENT_TAGGED_HCLASS_INDEX);
result.emplace(ElementsKind::HOLE_INT, ConstantIndex::ELEMENT_HOLE_INT_HCLASS_INDEX);
result.emplace(ElementsKind::HOLE_DOUBLE, ConstantIndex::ELEMENT_HOLE_DOUBLE_HCLASS_INDEX);
result.emplace(ElementsKind::HOLE_NUMBER, ConstantIndex::ELEMENT_HOLE_NUMBER_HCLASS_INDEX);
result.emplace(ElementsKind::HOLE_STRING, ConstantIndex::ELEMENT_HOLE_STRING_HCLASS_INDEX);
result.emplace(ElementsKind::HOLE_OBJECT, ConstantIndex::ELEMENT_HOLE_OBJECT_HCLASS_INDEX);
result.emplace(ElementsKind::HOLE_TAGGED, ConstantIndex::ELEMENT_HOLE_TAGGED_HCLASS_INDEX);
return result;
}
std::string Elements::GetString(ElementsKind kind)
{
return std::to_string(static_cast<uint32_t>(kind));
}
bool Elements::IsHole(ElementsKind kind)
{
static constexpr uint8_t EVEN_NUMBER = 2;
return static_cast<uint8_t>(kind) % EVEN_NUMBER == 1;
}
ElementsKind Elements::MergeElementsKind(ElementsKind curKind, ElementsKind newKind)
{
auto result = ElementsKind(static_cast<uint8_t>(curKind) | static_cast<uint8_t>(newKind));
ASSERT(result != ElementsKind::NONE);
result = FixElementsKind(result);
return result;
}
ElementsKind Elements::FixElementsKind(ElementsKind oldKind)
{
auto result = oldKind;
switch (result) {
case ElementsKind::NONE:
case ElementsKind::INT:
case ElementsKind::DOUBLE:
case ElementsKind::NUMBER:
case ElementsKind::STRING:
case ElementsKind::OBJECT:
case ElementsKind::HOLE_INT:
case ElementsKind::HOLE_DOUBLE:
case ElementsKind::HOLE_NUMBER:
case ElementsKind::HOLE_STRING:
case ElementsKind::HOLE_OBJECT:
break;
default:
if (IsHole(result)) {
result = ElementsKind::HOLE_TAGGED;
} else {
result = ElementsKind::TAGGED;
}
break;
}
return result;
}
ElementsKind Elements::ToElementsKind(JSTaggedValue value, ElementsKind kind)
{
ElementsKind valueKind = ElementsKind::NONE;
if (value.IsInt()) {
valueKind = ElementsKind::INT;
} else if (value.IsDouble()) {
valueKind = ElementsKind::DOUBLE;
} else if (value.IsString()) {
valueKind = ElementsKind::STRING;
} else if (value.IsHeapObject()) {
valueKind = ElementsKind::OBJECT;
} else if (value.IsHole()) {
valueKind = ElementsKind::HOLE;
} else {
valueKind = ElementsKind::TAGGED;
}
return MergeElementsKind(valueKind, kind);
}
} // namespace panda::ecmascript

63
ecmascript/elements.h Normal file
View File

@ -0,0 +1,63 @@
/*
* 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.
*/
#ifndef ECMASCRIPT_ELEMENTS_H
#define ECMASCRIPT_ELEMENTS_H
#include "ecmascript/global_env_constants.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/mem/c_containers.h"
namespace panda::ecmascript {
enum class ElementsKind : uint8_t {
NONE = 0x00UL,
HOLE = 0x01UL,
INT = 0x1UL << 1, // 2
DOUBLE = 0x1UL << 2, // 4
NUMBER = INT | DOUBLE, // 6
STRING = 0x1UL << 3, // 8
OBJECT = 0x1UL << 4, // 16
TAGGED = 0x1EUL, // 30
HOLE_INT = HOLE | INT,
HOLE_DOUBLE = HOLE | DOUBLE,
HOLE_NUMBER = HOLE | NUMBER,
HOLE_STRING = HOLE | STRING,
HOLE_OBJECT = HOLE | OBJECT,
HOLE_TAGGED = HOLE | TAGGED,
GENERIC = HOLE_TAGGED,
};
class Elements {
public:
static CMap<ElementsKind, ConstantIndex> InitializeHClassMap();
static std::string GetString(ElementsKind kind);
static bool IsHole(ElementsKind kind);
static bool IsGeneric(ElementsKind kind)
{
return kind == ElementsKind::GENERIC;
}
static bool IsNone(ElementsKind kind)
{
return kind == ElementsKind::NONE;
}
static ElementsKind MergeElementsKind(ElementsKind curKind, ElementsKind newKind);
static ElementsKind FixElementsKind(ElementsKind oldKind);
static ElementsKind ToElementsKind(JSTaggedValue value, ElementsKind kind);
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_ELEMENTS_H

View File

@ -648,4 +648,17 @@ void GlobalEnvConstants::InitClassConstructorOptimizedClass(ObjectFactory *facto
fastCall->SetCanFastCall(true);
SetConstant(ConstantIndex::CLASS_CONSTRUCTOR_OPTIMIZED_WITH_FAST_CALL_HCLASS_INDEX, fastCall);
}
void GlobalEnvConstants::InitElementKindHClass(const JSThread *thread, JSHandle<JSHClass> originHClass)
{
auto map = thread->GetArrayHClassIndexMap();
for (auto iter : map) {
JSHandle<JSHClass> hclass = originHClass;
if (iter.first != ElementsKind::GENERIC) {
hclass = JSHClass::Clone(thread, originHClass);
hclass->SetElementsKind(iter.first);
}
SetConstant(iter.second, hclass);
}
}
} // namespace panda::ecmascript

View File

@ -126,6 +126,19 @@ class ObjectFactory;
V(JSTaggedValue, AOTLiteralInfoClass, AOT_LITERAL_INFO_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, VTableClass, VTABLE_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ClassLiteralClass, CLASS_LITERAL_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementNoneClass, ELEMENT_NONE_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementIntClass, ELEMENT_INT_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementDoubleClass, ELEMENT_DOUBLE_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementNumberClass, ELEMENT_NUMBER_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementStringClass, ELEMENT_STRING_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementObjectClass, ELEMENT_OBJECT_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementTaggedClass, ELEMENT_TAGGED_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementHoleIntClass, ELEMENT_HOLE_INT_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementHoleDoubleClass, ELEMENT_HOLE_DOUBLE_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementHoleNumberClass, ELEMENT_HOLE_NUMBER_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementHoleStringClass, ELEMENT_HOLE_STRING_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementHoleObjectClass, ELEMENT_HOLE_OBJECT_HCLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ElementHoleTaggedClass, ELEMENT_HOLE_TAGGED_HCLASS_INDEX, ecma_roots_class)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define GLOBAL_ENV_CONSTANT_SPECIAL(V) \
@ -502,6 +515,8 @@ public:
void InitSpecialForSnapshot();
void InitClassConstructorOptimizedClass(ObjectFactory *factory);
void InitElementKindHClass(const JSThread *thread, JSHandle<JSHClass> originHClass);
void SetCachedLocales(JSTaggedValue value);
void SetConstant(ConstantIndex index, JSTaggedValue value);

View File

@ -26,7 +26,7 @@
namespace panda::ecmascript {
JSTaggedValue JSArray::LengthGetter([[maybe_unused]] JSThread *thread, const JSHandle<JSObject> &self)
{
return JSArray::Cast(*self)->GetLength();
return JSTaggedValue(JSArray::Cast(*self)->GetLength());
}
bool JSArray::LengthSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,

View File

@ -49,18 +49,19 @@ public:
// use first inlined property slot for array length
inline uint32_t GetArrayLength() const
{
return GetLength().GetArrayLength();
return GetLength();
}
inline void SetArrayLength(const JSThread *thread, uint32_t length)
inline void SetArrayLength([[maybe_unused]]const JSThread *thread, uint32_t length)
{
SetLength(thread, JSTaggedValue(length));
SetLength(length);
}
static constexpr size_t LENGTH_OFFSET = JSObject::SIZE;
ACCESSORS(Length, LENGTH_OFFSET, SIZE);
ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, TRACE_INDEX_OFFSET)
ACCESSORS_PRIMITIVE_FIELD(TraceIndex, uint32_t, TRACE_INDEX_OFFSET, SIZE)
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LENGTH_OFFSET, SIZE)
DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, SIZE, SIZE)
static const uint32_t MAX_ARRAY_INDEX = MAX_ELEMENT_INDEX;
DECL_DUMP()

View File

@ -19,6 +19,7 @@
#include "ecmascript/base/config.h"
#include "ecmascript/global_env.h"
#include "ecmascript/tagged_array.h"
#include "ecmascript/vtable.h"
#include "ecmascript/ic/proto_change_details.h"
#include "ecmascript/js_object-inl.h"
@ -149,7 +150,7 @@ void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, ui
SetIsPrototype(false);
SetHasDeleteProperty(false);
SetIsAllTaggedProp(true);
SetElementRepresentation(Representation::NONE);
SetElementsKind(ElementsKind::GENERIC);
SetTransitions(thread, JSTaggedValue::Undefined());
SetProtoChangeMarker(thread, JSTaggedValue::Null());
SetProtoChangeDetails(thread, JSTaggedValue::Null());
@ -208,6 +209,7 @@ void JSHClass::TransitionElementsToDictionary(const JSThread *thread, const JSHa
}
obj->GetJSHClass()->SetIsDictionaryElement(true);
obj->GetJSHClass()->SetIsStableElements(false);
obj->GetJSHClass()->SetElementsKind(ElementsKind::GENERIC);
}
JSHandle<JSHClass> JSHClass::SetPropertyOfObjHClass(const JSThread *thread, JSHandle<JSHClass> &jshclass,
@ -461,6 +463,57 @@ void JSHClass::TransitionForRepChange(const JSThread *thread, const JSHandle<JSO
// 4. Maybe Transition And Maintain subtypeing check
}
void JSHClass::TransitToElementsKind(const JSThread *thread, const JSHandle<JSArray> &array)
{
JSTaggedValue elements = array->GetElements();
if (!elements.IsTaggedArray()) {
return;
}
ElementsKind newKind = ElementsKind::NONE;
auto elementArray = TaggedArray::Cast(elements);
int length = elementArray->GetLength();
for (int i = 0; i < length; i++) {
JSTaggedValue value = elementArray->Get(i);
newKind = Elements::ToElementsKind(value, newKind);
}
ElementsKind current = array->GetJSHClass()->GetElementsKind();
if (newKind == current) {
return;
}
auto arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
if (arrayHClassIndexMap.find(newKind) != arrayHClassIndexMap.end()) {
auto index = static_cast<size_t>(thread->GetArrayHClassIndexMap().at(newKind));
auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(index);
JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
array->SetClass(hclass);
}
}
void JSHClass::TransitToElementsKind(
const JSThread *thread, const JSHandle<JSObject> &object, const JSHandle<JSTaggedValue> &value, ElementsKind kind)
{
if (!object->IsJSArray()) {
return;
}
ElementsKind current = object->GetJSHClass()->GetElementsKind();
if (Elements::IsGeneric(current)) {
return;
}
auto newKind = Elements::ToElementsKind(value.GetTaggedValue(), kind);
// Merge current kind and new kind
newKind = Elements::MergeElementsKind(current, newKind);
if (newKind == current) {
return;
}
auto arrayHClassIndexMap = thread->GetArrayHClassIndexMap();
if (arrayHClassIndexMap.find(newKind) != arrayHClassIndexMap.end()) {
auto index = static_cast<size_t>(thread->GetArrayHClassIndexMap().at(newKind));
auto hclassVal = thread->GlobalConstants()->GetGlobalConstantObject(index);
JSHClass *hclass = JSHClass::Cast(hclassVal.GetTaggedObject());
object->SetClass(hclass);
}
}
JSHandle<JSTaggedValue> JSHClass::EnableProtoChangeMarker(const JSThread *thread, const JSHandle<JSHClass> &jshclass)
{
JSTaggedValue proto = jshclass->GetPrototype();
@ -737,6 +790,9 @@ bool JSHClass::DumpForProfile(const JSHClass *hclass, PGOHClassLayoutDesc &desc,
if (hclass->IsDictionaryMode()) {
return false;
}
if (kind == PGOObjKind::ELEMENT) {
desc.UpdateElementKind(hclass->GetElementsKind());
}
LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
int element = static_cast<int>(hclass->NumberOfProps());

View File

@ -17,6 +17,7 @@
#define ECMASCRIPT_JS_HCLASS_H
#include "ecmascript/ecma_macros.h"
#include "ecmascript/elements.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/mem/tagged_object.h"
#include "ecmascript/mem/barriers.h"
@ -289,14 +290,14 @@ enum class JSType : uint8_t {
class JSHClass : public TaggedObject {
public:
static constexpr int TYPE_BITFIELD_NUM = 8;
static constexpr int LEVEL_BTTFIELD_NUM = 5;
static constexpr int LEVEL_BTTFIELD_NUM = 3;
using ObjectTypeBits = BitField<JSType, 0, TYPE_BITFIELD_NUM>; // 8
using CallableBit = ObjectTypeBits::NextFlag;
using ConstructorBit = CallableBit::NextFlag; // 10
using ExtensibleBit = ConstructorBit::NextFlag;
using IsPrototypeBit = ExtensibleBit::NextFlag;
using ElementRepresentationBits = IsPrototypeBit::NextField<Representation, 3>; // 3 means next 3 bit
using DictionaryElementBits = ElementRepresentationBits::NextFlag; // 16
using ElementsKindBits = IsPrototypeBit::NextField<ElementsKind, 5>; // 5 means next 5 bit
using DictionaryElementBits = ElementsKindBits::NextFlag; // 16
using IsDictionaryBit = DictionaryElementBits::NextFlag; // 17
using IsStableElementsBit = IsDictionaryBit::NextFlag; // 18
using HasConstructorBits = IsStableElementsBit::NextFlag; // 19
@ -356,6 +357,9 @@ public:
static void TransitionToDictionary(const JSThread *thread, const JSHandle<JSObject> &obj);
static void TransitionForRepChange(const JSThread *thread, const JSHandle<JSObject> &receiver,
const JSHandle<JSTaggedValue> &key, PropertyAttributes attr);
static void TransitToElementsKind(const JSThread *thread, const JSHandle<JSArray> &array);
static void TransitToElementsKind(const JSThread *thread, const JSHandle<JSObject> &object,
const JSHandle<JSTaggedValue> &value, ElementsKind kind = ElementsKind::NONE);
static JSHandle<JSTaggedValue> EnableProtoChangeMarker(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
@ -1473,17 +1477,17 @@ public:
return GetObjectType() == JSType::JS_MODULE_NAMESPACE;
}
inline void SetElementRepresentation(Representation representation)
inline void SetElementsKind(ElementsKind kind)
{
uint32_t bits = GetBitField();
uint32_t newVal = ElementRepresentationBits::Update(bits, representation);
uint32_t newVal = ElementsKindBits::Update(bits, kind);
SetBitField(newVal);
}
inline Representation GetElementRepresentation() const
inline ElementsKind GetElementsKind() const
{
uint32_t bits = GetBitField();
return ElementRepresentationBits::Decode(bits);
return ElementsKindBits::Decode(bits);
}
inline void SetLevel(uint8_t level)

View File

@ -223,28 +223,28 @@ inline bool JSObject::IsTypedArray() const
return GetJSHClass()->IsTypedArray();
}
JSTaggedValue JSObject::ConvertValueWithRep(uint32_t index, JSTaggedValue value)
std::pair<bool, JSTaggedValue> JSObject::ConvertValueWithRep(uint32_t index, JSTaggedValue value)
{
auto layout = LayoutInfo::Cast(GetJSHClass()->GetLayout().GetTaggedObject());
auto attr = layout->GetAttr(index);
if (attr.IsDoubleRep()) {
if (value.IsInt()) {
double doubleValue = value.GetInt();
return JSTaggedValue(bit_cast<JSTaggedType>(doubleValue));
return std::pair(true, JSTaggedValue(bit_cast<JSTaggedType>(doubleValue)));
} else if (value.IsDouble()) {
return JSTaggedValue(bit_cast<JSTaggedType>(value.GetDouble()));
return std::pair(true, JSTaggedValue(bit_cast<JSTaggedType>(value.GetDouble())));
} else {
UNREACHABLE();
return std::pair(false, value);
}
} else if (attr.IsIntRep()) {
if (value.IsInt()) {
int intValue = value.GetInt();
return JSTaggedValue(static_cast<JSTaggedType>(intValue));
return std::pair(true, JSTaggedValue(static_cast<JSTaggedType>(intValue)));
} else {
UNREACHABLE();
return std::pair(false, value);
}
}
return value;
return std::pair(true, value);
}
void JSObject::SetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index, JSTaggedValue value)

View File

@ -237,6 +237,7 @@ bool JSObject::AddElementInternal(JSThread *thread, const JSHandle<JSObject> &re
const JSHandle<JSTaggedValue> &value, PropertyAttributes attr)
{
bool isDictionary = receiver->GetJSHClass()->IsDictionaryElement();
ElementsKind kind = ElementsKind::NONE;
if (receiver->IsJSArray()) {
DISALLOW_GARBAGE_COLLECTION;
JSArray *arr = JSArray::Cast(*receiver);
@ -246,6 +247,9 @@ bool JSObject::AddElementInternal(JSThread *thread, const JSHandle<JSObject> &re
return false;
}
arr->SetArrayLength(thread, index + 1);
if (index > oldLength) {
kind = ElementsKind::HOLE;
}
}
}
thread->NotifyStableArrayElementsGuardians(receiver);
@ -273,6 +277,7 @@ bool JSObject::AddElementInternal(JSThread *thread, const JSHandle<JSObject> &re
elements = *JSObject::GrowElementsCapacity(thread, receiver, index + 1);
}
elements->Set(thread, index, value);
JSHClass::TransitToElementsKind(thread, receiver, value, kind);
return true;
}
@ -2125,17 +2130,30 @@ JSHandle<JSObject> JSObject::CreateObjectFromProperties(const JSThread *thread,
}
if (propsLen <= PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES) {
JSHandle<JSObject> obj = factory->NewOldSpaceObjLiteralByHClass(properties, propsLen);
ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
if (ihcVal.IsJSHClass()) {
bool isSuccess = true;
JSHClass *ihc = JSHClass::Cast(ihcVal.GetTaggedObject());
JSHClass *oldHC = obj->GetJSHClass();
ihc->SetPrototype(thread, oldHC->GetPrototype());
obj->SetClass(ihc);
for (size_t i = 0; i < propsLen; i++) {
auto value = obj->ConvertValueWithRep(i, properties->Get(i * 2 + 1));
if (!value.first) {
isSuccess = false;
break;
}
obj->SetPropertyInlinedPropsWithRep(thread, i, value.second);
}
if (isSuccess) {
return obj;
}
// The layout representation of ihc is inaccurate and needs to be rolled back to the old HClass
obj->SetClass(oldHC);
}
ASSERT_PRINT(obj->IsECMAObject(), "Obj is not a valid object");
for (size_t i = 0; i < propsLen; i++) {
// 2: literal contains a pair of key-value
auto value = obj->ConvertValueWithRep(i, properties->Get(i * 2 + 1));
obj->SetPropertyInlinedPropsWithRep(thread, i, value);
obj->SetPropertyInlinedProps(thread, i, properties->Get(i * 2 + 1));
}
return obj;
} else {

View File

@ -615,7 +615,7 @@ public:
static JSHandle<NameDictionary> TransitionToDictionary(const JSThread *thread, const JSHandle<JSObject> &receiver);
inline JSTaggedValue ConvertValueWithRep(uint32_t index, JSTaggedValue value);
inline std::pair<bool, JSTaggedValue> ConvertValueWithRep(uint32_t index, JSTaggedValue value);
inline void SetPropertyInlinedPropsWithRep(const JSThread *thread, uint32_t index, JSTaggedValue value);
template <bool needBarrier = true>
inline void SetPropertyInlinedProps(const JSThread *thread, uint32_t index, JSTaggedValue value);

View File

@ -581,7 +581,7 @@ bool JSSerializer::WriteJSArray(const JSHandle<JSTaggedValue> &value)
if (!WritePlainObject(value)) {
return false;
}
uint32_t arrayLength = static_cast<uint32_t>(array->GetLength().GetInt());
uint32_t arrayLength = array->GetLength();
if (!WriteInt(arrayLength)) {
return false;
}
@ -1443,7 +1443,7 @@ JSHandle<JSTaggedValue> JSDeserializer::ReadJSArray()
if (!JudgeType(SerializationUID::INT32) || !ReadInt(&arrLength)) {
return JSHandle<JSTaggedValue>();
}
jsArray->SetLength(thread_, JSTaggedValue(arrLength));
jsArray->SetLength(arrLength);
return arrayTag;
}

View File

@ -25,6 +25,7 @@
#include "ecmascript/compiler/interpreter_stub.h"
#include "ecmascript/compiler/rt_call_signature.h"
#include "ecmascript/dfx/vm_thread_control.h"
#include "ecmascript/elements.h"
#include "ecmascript/frames.h"
#include "ecmascript/global_env_constants.h"
#include "ecmascript/mem/visitor.h"
@ -316,6 +317,11 @@ public:
return glueData_.globalConst_;
}
const CMap<ElementsKind, ConstantIndex> &GetArrayHClassIndexMap() const
{
return arrayHClassIndexMap_;
}
void NotifyStableArrayElementsGuardians(JSHandle<JSObject> receiver);
bool IsStableArrayElementsGuardiansInvalid() const
@ -876,6 +882,11 @@ private:
currentContext_ = context;
}
void SetArrayHClassIndexMap(const CMap<ElementsKind, ConstantIndex> &map)
{
arrayHClassIndexMap_ = map;
}
void DumpStack() DUMP_API_ATTR;
static size_t GetAsmStackLimit();
@ -922,6 +933,8 @@ private:
bool isFrameDropped_ {false};
CMap<ElementsKind, ConstantIndex> arrayHClassIndexMap_;
CVector<EcmaContext *> contexts_;
EcmaContext *currentContext_ {nullptr};
friend class GlobalHandleCollection;

View File

@ -77,6 +77,7 @@ public:
static constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/";
static constexpr int PACKAGE_NAME_LEN = 8;
static constexpr int TYPE_SUMMARY_OFFSET_NOT_FOUND = 0;
static constexpr int32_t PF_OFFSET = 0;
JSPandaFile(const panda_file::File *pf, const CString &descriptor);
~JSPandaFile();
@ -385,13 +386,13 @@ private:
static constexpr size_t VERSION_SIZE = 4;
static constexpr std::array<uint8_t, VERSION_SIZE> OLD_VERSION {0, 0, 0, 2};
const panda_file::File *pf_ {nullptr};
uint32_t constpoolIndex_ {0};
uint32_t checksum_ {0};
CUnorderedMap<uint32_t, MethodLiteral *> methodLiteralMap_;
CUnorderedMap<uint32_t, uint64_t> constpoolMap_;
uint32_t numMethods_ {0};
MethodLiteral *methodLiterals_ {nullptr};
const panda_file::File *pf_ {nullptr};
CString desc_;
uint32_t anFileInfoIndex_ {INVALID_INDEX};
bool isNewVersion_ {false};

View File

@ -292,8 +292,6 @@ public:
JSObject::DefinePropertyByLiteral(thread, obj, key, valueHandle);
}
PGOProfiler *profiler = thread->GetEcmaVM()->GetPGOProfiler();
profiler->InsertLiteralId(JSTaggedType(obj->GetJSHClass()), id);
val = obj.GetTaggedValue();
break;
}
@ -303,6 +301,9 @@ public:
uint32_t length = literal->GetLength();
JSHandle<JSArray> arr(JSArray::ArrayCreate(thread, JSTaggedNumber(length), ArrayMode::LITERAL));
arr->SetElements(thread, literal);
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
JSHClass::TransitToElementsKind(thread, arr);
}
val = arr.GetTaggedValue();
break;
}

View File

@ -1037,7 +1037,7 @@ void ObjectFactory::InitializeJSObject(const JSHandle<JSObject> &obj, const JSHa
}
#endif
case JSType::JS_ARRAY: {
JSArray::Cast(*obj)->SetLength(thread_, JSTaggedValue(0));
JSArray::Cast(*obj)->SetLength(0);
ASSERT(!obj->GetJSHClass()->IsDictionaryMode());
auto accessor = thread_->GlobalConstants()->GetArrayLengthAccessor();
JSArray::Cast(*obj)->SetPropertyInlinedProps(thread_, JSArray::LENGTH_INLINE_PROPERTY_INDEX, accessor);
@ -4040,7 +4040,7 @@ JSHandle<JSArray> ObjectFactory::NewJSStableArrayWithElements(const JSHandle<Tag
JSHandle<JSArray> array = JSHandle<JSArray>::Cast(NewJSObject(cls));
array->SetElements(thread_, elements);
array->SetLength(thread_, JSTaggedValue(elements->GetLength()));
array->SetLength(elements->GetLength());
auto accessor = thread_->GlobalConstants()->GetArrayLengthAccessor();
array->SetPropertyInlinedProps(thread_, JSArray::LENGTH_INLINE_PROPERTY_INDEX, accessor);
return array;

View File

@ -484,6 +484,7 @@ bool ObjectOperator::UpdateDataValue(const JSHandle<JSObject> &receiver, const J
return true;
}
elements->Set(thread_, GetIndex(), value.GetTaggedValue());
JSHClass::TransitToElementsKind(thread_, receiver, value);
return true;
}

View File

@ -154,7 +154,7 @@ void PGOProfiler::ProfileDefineClass(JSThread *thread, JSTaggedType func, int32_
}
}
void PGOProfiler::ProfileCreateObject(JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj)
void PGOProfiler::ProfileCreateObject(JSTaggedType func, int32_t offset, JSTaggedType newObj, int32_t traceId)
{
if (!isEnable_) {
return;
@ -177,23 +177,26 @@ void PGOProfiler::ProfileCreateObject(JSTaggedType func, int32_t offset, JSTagge
auto jsMethod = Method::Cast(method);
auto funcMethodId = jsMethod->GetMethodId();
auto originObjValue = JSTaggedValue(originObj);
auto newObjValue = JSTaggedValue(newObj);
if (!originObjValue.IsJSObject() || !newObjValue.IsJSObject()) {
return;
}
auto originHclass = JSObject::Cast(originObjValue)->GetJSHClass();
auto iter = literalIds_.find(JSTaggedType(originHclass));
if (iter == literalIds_.end()) {
if (!newObjValue.IsJSObject()) {
return;
}
auto newHClass = JSObject::Cast(newObjValue) ->GetJSHClass();
InsertLiteralId(JSTaggedType(newHClass), iter->second);
auto currentType = PGOSampleType::CreateClassType(iter->second.GetOffset());
auto superType = PGOSampleType::CreateClassType(0);
recordInfos_->AddDefine(recordName, funcMethodId, offset, currentType, superType);
recordInfos_->AddLayout(currentType, JSTaggedType(newHClass), PGOObjKind::LOCAL);
if (newHClass->IsJSArray()) {
auto array = JSArray::Cast(newObjValue);
auto currentType = PGOSampleType::CreateClassType(array->GetTraceIndex());
auto superType = PGOSampleType::CreateClassType(0);
recordInfos_->AddDefine(recordName, funcMethodId, offset, currentType, superType);
PGOObjKind kind = PGOObjKind::ELEMENT;
recordInfos_->AddLayout(currentType, JSTaggedType(newHClass), kind);
} else {
InsertLiteralId(JSTaggedType(newHClass), traceId);
auto currentType = PGOSampleType::CreateClassType(traceId);
auto superType = PGOSampleType::CreateClassType(0);
recordInfos_->AddDefine(recordName, funcMethodId, offset, currentType, superType);
PGOObjKind kind = PGOObjKind::LOCAL;
recordInfos_->AddLayout(currentType, JSTaggedType(newHClass), kind);
}
}
}
@ -229,13 +232,26 @@ void PGOProfiler::ProfileObjLayout(JSThread *thread, JSTaggedType func, int32_t
ctor = holder;
kind = PGOObjKind::CONSTRUCTOR;
} else if (hclass->IsLiteral()) {
auto iter = literalIds_.find(JSTaggedType(hclass));
if (iter != literalIds_.end()) {
PGOObjectInfo info(ClassType(iter->second.GetOffset()), kind);
auto iter = traceIds_.find(JSTaggedType(hclass));
if (iter != traceIds_.end()) {
PGOObjectInfo info(ClassType(iter->second), kind);
auto methodId = jsMethod->GetMethodId();
recordInfos_->AddObjectInfo(recordName, methodId, offset, info);
if (store) {
auto type = PGOSampleType::CreateClassType(iter->second.GetOffset());
auto type = PGOSampleType::CreateClassType(iter->second);
recordInfos_->AddLayout(type, JSTaggedType(hclass), kind);
}
}
return;
} else if (hclass->IsJSArray()) {
kind = PGOObjKind::ELEMENT;
auto array = JSArray::Cast(holder);
if (array->GetTraceIndex() != 0) {
PGOObjectInfo info(ClassType(array->GetTraceIndex()), kind);
auto methodId = jsMethod->GetMethodId();
recordInfos_->AddObjectInfo(recordName, methodId, offset, info);
if (store) {
auto type = PGOSampleType::CreateClassType(array->GetTraceIndex());
recordInfos_->AddLayout(type, JSTaggedType(hclass), kind);
}
}
@ -263,17 +279,34 @@ void PGOProfiler::ProfileObjLayout(JSThread *thread, JSTaggedType func, int32_t
}
}
void PGOProfiler::InsertLiteralId(JSTaggedType hclass, EntityId literalId)
void PGOProfiler::InsertLiteralId(JSTaggedType hclass, int32_t traceId)
{
if (!isEnable_) {
return;
}
auto iter = literalIds_.find(hclass);
if (iter != literalIds_.end()) {
if (!(iter->second == literalId)) {
literalIds_.erase(iter);
}
auto iter = traceIds_.find(hclass);
if (iter != traceIds_.end() && iter->second != traceId) {
traceIds_.erase(iter);
}
traceIds_.emplace(hclass, traceId);
}
void PGOProfiler::ProcessReferences(const WeakRootVisitor &visitor)
{
if (!isEnable_) {
return;
}
for (auto iter = traceIds_.begin(); iter != traceIds_.end();) {
JSTaggedType object = iter->first;
auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
if (fwd == nullptr) {
iter = traceIds_.erase(iter);
continue;
}
if (fwd != reinterpret_cast<TaggedObject *>(object)) {
UNREACHABLE();
}
++iter;
}
literalIds_.emplace(hclass, literalId);
}
} // namespace panda::ecmascript

View File

@ -31,7 +31,7 @@ public:
void ProfileCall(JSTaggedType func, JSTaggedType callTarget, int32_t pcOffset = -1,
SampleMode mode = SampleMode::CALL_MODE, int32_t incCount = 1);
void ProfileOpType(JSTaggedType func, int32_t offset, uint32_t type);
void ProfileCreateObject(JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj);
void ProfileCreateObject(JSTaggedType func, int32_t offset, JSTaggedType newObj, int32_t traceId);
void ProfileDefineClass(JSThread *thread, JSTaggedType func, int32_t offset, JSTaggedType ctor);
void ProfileObjLayout(JSThread *thread, JSTaggedType func, int32_t offset, JSTaggedType object, bool store);
void SetSaveTimestamp(std::chrono::system_clock::time_point timestamp)
@ -39,7 +39,8 @@ public:
saveTimestamp_ = timestamp;
}
void InsertLiteralId(JSTaggedType hclass, EntityId literalId);
void InsertLiteralId(JSTaggedType hclass, int32_t traceId);
void ProcessReferences(const WeakRootVisitor &visitor);
private:
static constexpr uint32_t MERGED_EVERY_COUNT = 20;
@ -73,7 +74,7 @@ private:
bool isEnable_ {false};
uint32_t methodCount_ {0};
std::chrono::system_clock::time_point saveTimestamp_;
CMap<JSTaggedType, EntityId> literalIds_;
CMap<JSTaggedType, int32_t> traceIds_;
std::unique_ptr<PGORecordDetailInfos> recordInfos_;
friend class PGOProfilerManager;
};

View File

@ -482,6 +482,7 @@ size_t PGOHClassLayoutDescInner::CaculateSize(const PGOHClassLayoutDesc &desc)
size += static_cast<size_t>(PGOLayoutDescInfo::Size(key.size()));
}
}
size += sizeof(ElementsKind);
return size;
}
@ -489,8 +490,14 @@ std::string PGOHClassLayoutDescInner::GetTypeString(const PGOHClassLayoutDesc &d
{
std::string text;
text += desc.GetClassType().GetTypeString();
text += TYPE_SEPARATOR + SPACE;
text += desc.GetSuperClassType().GetTypeString();
if (!desc.GetSuperClassType().IsNone()) {
text += TYPE_SEPARATOR + SPACE;
text += desc.GetSuperClassType().GetTypeString();
}
if (!Elements::IsNone(desc.GetElementsKind())) {
text += TYPE_SEPARATOR + SPACE;
text += Elements::GetString(desc.GetElementsKind());
}
text += BLOCK_AND_ARRAY_START;
bool isLayoutFirst = true;
for (const auto &layoutDesc : desc.GetLayoutDesc()) {
@ -1088,11 +1095,11 @@ void PGORecordDetailInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *cons
return;
}
if (header->SupportTrackField()) {
ParseFromBinaryForLayout(&addr);
ParseFromBinaryForLayout(&addr, header);
}
}
bool PGORecordDetailInfos::ParseFromBinaryForLayout(void **buffer)
bool PGORecordDetailInfos::ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header)
{
SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
for (uint32_t i = 0; i < secInfo.number_; i++) {
@ -1101,7 +1108,7 @@ bool PGORecordDetailInfos::ParseFromBinaryForLayout(void **buffer)
LOG_ECMA(INFO) << "Binary format error!";
continue;
}
moduleLayoutDescInfos_.emplace(info->Convert());
moduleLayoutDescInfos_.emplace(info->Convert(header));
}
return true;
}
@ -1153,13 +1160,14 @@ bool PGORecordDetailInfos::ProcessToBinaryForLayout(
return false;
}
auto classType = PGOSampleType(typeInfo.GetClassType());
auto elementsKind = typeInfo.GetElementsKind();
size_t size = PGOHClassLayoutDescInner::CaculateSize(typeInfo);
if (size == 0) {
continue;
}
auto superType = PGOSampleType(typeInfo.GetSuperClassType());
void *addr = allocator->Allocate(size);
auto descInfos = new (addr) PGOHClassLayoutDescInner(size, classType, superType);
auto descInfos = new (addr) PGOHClassLayoutDescInner(size, classType, superType, elementsKind);
descInfos->Merge(typeInfo);
stream.write(reinterpret_cast<char *>(descInfos), size);
allocator->Delete(addr);
@ -1265,7 +1273,7 @@ void PGORecordSimpleInfos::ParseFromBinary(void *buffer, PGOProfilerHeader *cons
return;
}
if (header->SupportTrackField()) {
ParseFromBinaryForLayout(&addr);
ParseFromBinaryForLayout(&addr, header);
}
}
@ -1292,7 +1300,7 @@ void PGORecordSimpleInfos::Merge(const PGORecordSimpleInfos &simpleInfos)
}
}
bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer)
bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header)
{
SectionInfo secInfo = base::ReadBuffer<SectionInfo>(buffer);
for (uint32_t i = 0; i < secInfo.number_; i++) {
@ -1301,7 +1309,7 @@ bool PGORecordSimpleInfos::ParseFromBinaryForLayout(void **buffer)
LOG_ECMA(INFO) << "Binary format error!";
continue;
}
moduleLayoutDescInfos_.emplace(info->Convert());
moduleLayoutDescInfos_.emplace(info->Convert(header));
}
return true;
}

View File

@ -103,10 +103,11 @@ public:
static constexpr VersionType USE_HCLASS_TYPE_MINI_VERSION = {0, 0, 0, 5};
static constexpr VersionType FILE_CONSISTENCY_MINI_VERSION = {0, 0, 0, 6};
static constexpr VersionType TRACK_FIELD_MINI_VERSION = {0, 0, 0, 7};
static constexpr VersionType ELEMENTS_KIND_MINI_VERSION = {0, 0, 0, 8};
static constexpr VersionType FILE_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
static constexpr VersionType HEADER_SIZE_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
static constexpr VersionType ELASTIC_HEADER_MINI_VERSION = FILE_CONSISTENCY_MINI_VERSION;
static constexpr VersionType LAST_VERSION = {0, 0, 0, 7};
static constexpr VersionType LAST_VERSION = {0, 0, 0, 8};
static constexpr size_t SECTION_SIZE = 3;
static constexpr size_t PANDA_FILE_SECTION_INDEX = 0;
static constexpr size_t RECORD_INFO_SECTION_INDEX = 1;
@ -227,6 +228,11 @@ public:
return CompatibleVerify(TRACK_FIELD_MINI_VERSION);
}
bool SupportElementsKind() const
{
return CompatibleVerify(ELEMENTS_KIND_MINI_VERSION);
}
NO_COPY_SEMANTIC(PGOProfilerHeader);
NO_MOVE_SEMANTIC(PGOProfilerHeader);
@ -699,8 +705,11 @@ private:
class PGOHClassLayoutDescInner {
public:
PGOHClassLayoutDescInner(size_t size, PGOSampleType type, PGOSampleType superType)
: size_(size), type_(type), superType_(superType) {}
PGOHClassLayoutDescInner(size_t size, PGOSampleType type, PGOSampleType superType, ElementsKind kind)
: size_(size), type_(type), superType_(superType)
{
SetElementsKind(kind);
}
static size_t CaculateSize(const PGOHClassLayoutDesc &desc);
static std::string GetTypeString(const PGOHClassLayoutDesc &desc);
@ -717,7 +726,7 @@ public:
return type_;
}
PGOHClassLayoutDesc Convert()
PGOHClassLayoutDesc Convert(PGOProfilerHeader *const header)
{
PGOHClassLayoutDesc desc(GetType().GetClassType());
desc.SetSuperClassType(superType_.GetClassType());
@ -734,6 +743,9 @@ public:
desc.AddCtorKeyAndDesc(descInfo->GetKey(), descInfo->GetHandler());
descInfo = GetNext(descInfo);
}
if (header->SupportElementsKind()) {
desc.SetElementsKind(GetElementsKind());
}
return desc;
}
@ -788,6 +800,21 @@ private:
return reinterpret_cast<PGOLayoutDescInfo *>(reinterpret_cast<uintptr_t>(current) + current->Size());
}
void SetElementsKind(ElementsKind kind)
{
*reinterpret_cast<ElementsKind *>(GetEnd() - sizeof(ElementsKind)) = kind;
}
ElementsKind GetElementsKind() const
{
return *reinterpret_cast<const ElementsKind *>(GetEnd() - sizeof(ElementsKind));
}
uintptr_t GetEnd() const
{
return reinterpret_cast<uintptr_t>(this) + Size();
}
int32_t size_;
PGOSampleType type_;
PGOSampleType superType_;
@ -1029,7 +1056,7 @@ public:
private:
PGOMethodInfoMap *GetMethodInfoMap(const CString &recordName);
bool ParseFromBinaryForLayout(void **buffer);
bool ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header);
bool ProcessToBinaryForLayout(NativeAreaAllocator *allocator, const SaveTask *task, std::fstream &stream) const;
uint32_t hotnessThreshold_ {2};
@ -1142,7 +1169,7 @@ public:
NO_MOVE_SEMANTIC(PGORecordSimpleInfos);
private:
bool ParseFromBinaryForLayout(void **buffer);
bool ParseFromBinaryForLayout(void **buffer, PGOProfilerHeader *const header);
uint32_t hotnessThreshold_ {2};
NativeAreaAllocator nativeAreaAllocator_;

View File

@ -16,10 +16,16 @@
#include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
namespace panda::ecmascript {
void PGOHClassLayoutDesc::UpdateElementKind(const ElementsKind kind)
{
kind_ = kind;
}
void PGOHClassLayoutDesc::UpdateKeyAndDesc(const CString &key, const PGOHandler &handler, PGOObjKind kind)
{
switch (kind) {
case PGOObjKind::LOCAL:
case PGOObjKind::ELEMENT:
UpdateKeyAndDesc(key, handler, layoutDesc_);
break;
case PGOObjKind::PROTOTYPE:

View File

@ -19,6 +19,7 @@
#include <stdint.h>
#include <string>
#include "ecmascript/elements.h"
#include "ecmascript/mem/c_containers.h"
#include "ecmascript/pgo_profiler/pgo_profiler_type.h"
#include "ecmascript/property_attributes.h"
@ -145,6 +146,16 @@ public:
return ctorLayoutDesc_;
}
ElementsKind GetElementsKind() const
{
return kind_;
}
void SetElementsKind(ElementsKind kind)
{
kind_ = kind;
}
bool FindProperty(const CString &key, PropertyDesc &desc) const
{
for (const auto &iter : layoutDesc_) {
@ -171,6 +182,7 @@ public:
ctorLayoutDesc_.emplace_back(key, handler);
}
void UpdateElementKind(const ElementsKind kind);
void UpdateKeyAndDesc(const CString &key, const PGOHandler &handler, PGOObjKind kind);
bool FindDescWithKey(const CString &key, PGOHandler &handler) const;
@ -187,6 +199,7 @@ private:
ClassType type_;
ClassType superType_;
ElementsKind kind_;
LayoutDesc layoutDesc_;
LayoutDesc ptLayoutDesc_;
LayoutDesc ctorLayoutDesc_;

View File

@ -309,17 +309,13 @@ enum class PGOObjKind {
LOCAL,
PROTOTYPE,
CONSTRUCTOR,
ELEMENT,
};
class PGOObjectInfo {
public:
PGOObjectInfo() : type_(ClassType()), objKind_(PGOObjKind::LOCAL) {}
PGOObjectInfo(ClassType type, PGOObjKind kind) : type_(type), objKind_(PGOObjKind::LOCAL)
{
if (kind == PGOObjKind::CONSTRUCTOR) {
objKind_ = kind;
}
}
PGOObjectInfo(ClassType type, PGOObjKind kind) : type_(type), objKind_(kind) {}
std::string GetInfoString() const
{
@ -327,6 +323,10 @@ public:
result += "(";
if (objKind_ == PGOObjKind::CONSTRUCTOR) {
result += "c";
} else if (objKind_ == PGOObjKind::PROTOTYPE) {
result += "p";
} else if (objKind_ == PGOObjKind::ELEMENT) {
result += "e";
} else {
result += "l";
}

View File

@ -23,6 +23,7 @@ test_js_files = [
"op_type_test",
"class_test",
"call_test",
"array_test",
]
foreach(file, test_js_files) {

View File

@ -837,6 +837,68 @@ HWTEST_F_L0(PGOProfilerTest, OpTypeTest)
unlink("ark-profiler16/modules.ap");
rmdir("ark-profiler16/");
}
HWTEST_F_L0(PGOProfilerTest, ArrayProfileTest)
{
mkdir("ark-profiler18/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
const char *targetRecordName = "array_test";
std::shared_ptr<JSPandaFile> jsPandaFile = ExecuteAndLoadJSPandaFile("ark-profiler18/", targetRecordName);
ASSERT_NE(jsPandaFile, nullptr);
uint32_t checksum = jsPandaFile->GetChecksum();
// Loader
PGOProfilerDecoder decoder("ark-profiler18/modules.ap", 1);
ASSERT_TRUE(decoder.LoadAndVerify(checksum));
auto methodLiterals = jsPandaFile->GetMethodLiteralMap();
for (auto iter : methodLiterals) {
auto methodLiteral = iter.second;
auto methodId = methodLiteral->GetMethodId();
auto methodName = methodLiteral->GetMethodName(jsPandaFile.get(), methodId);
decoder.MatchAndMarkMethod(targetRecordName, methodName, methodId);
ASSERT_TRUE(decoder.Match(targetRecordName, methodId));
auto callback = [methodName, &decoder, jsPandaFile](uint32_t offset, PGOType *type) {
if (type->IsScalarOpType()) {
auto sampleType = *reinterpret_cast<PGOSampleType *>(type);
if (sampleType.IsClassType()) {
ASSERT_EQ(std::string(methodName), "func_main_0");
PGOHClassLayoutDesc *desc;
if (!decoder.GetHClassLayoutDesc(sampleType, &desc)) {
return;
}
ASSERT_EQ(desc->GetCtorLayoutDesc().size(), 0);
ASSERT_EQ(desc->GetPtLayoutDesc().size(), 0);
ASSERT_EQ(desc->GetLayoutDesc().size(), 1);
}
} else if (type->IsRwOpType()) {
auto pgoRWOpType = *reinterpret_cast<PGORWOpType *>(type);
if (std::string(methodName) == "foo") {
ASSERT_TRUE(pgoRWOpType.GetCount() == 3);
auto classType = PGOSampleType(pgoRWOpType.GetObjectInfo(0).GetClassType());
PGOHClassLayoutDesc *desc;
ASSERT_TRUE(decoder.GetHClassLayoutDesc(classType, &desc));
ASSERT_EQ(desc->GetElementsKind(), ElementsKind::NUMBER);
classType = PGOSampleType(pgoRWOpType.GetObjectInfo(1).GetClassType());
ASSERT_TRUE(decoder.GetHClassLayoutDesc(classType, &desc));
ASSERT_EQ(desc->GetElementsKind(), ElementsKind::HOLE_NUMBER);
classType = PGOSampleType(pgoRWOpType.GetObjectInfo(2).GetClassType());
ASSERT_TRUE(decoder.GetHClassLayoutDesc(classType, &desc));
ASSERT_EQ(desc->GetElementsKind(), ElementsKind::HOLE_TAGGED);
} else if (std::string(methodName) == "foo1") {
ASSERT_TRUE(pgoRWOpType.GetCount() == 1);
auto classType = PGOSampleType(pgoRWOpType.GetObjectInfo(0).GetClassType());
PGOHClassLayoutDesc *desc;
ASSERT_TRUE(decoder.GetHClassLayoutDesc(classType, &desc));
ASSERT_EQ(desc->GetElementsKind(), ElementsKind::TAGGED);
}
}
};
decoder.GetTypeInfo(jsPandaFile.get(), targetRecordName, methodLiteral, callback);
}
unlink("ark-profiler18/modules.ap");
rmdir("ark-profiler18/");
}
#endif
HWTEST_F_L0(PGOProfilerTest, FileConsistencyCheck)

View File

@ -0,0 +1,33 @@
/*
* 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.
*/
let a = [1, 2, 3]
let b = [1, , 3]
let c = [1, 2, "test", 1]
let d = [1, 2, 3, 4.23]
function foo(p) {
p[1] = 1.1
}
function foo1(p) {
p[2] = "test";
}
foo(a)
foo(b)
foo(c)
foo1(d)
c[6] = 1

View File

@ -387,6 +387,23 @@ DEF_RUNTIME_STUBS(CopyAndUpdateObjLayout)
return JSTaggedValue::Hole().GetRawData();
}
DEF_RUNTIME_STUBS(UpdateHClassForElementsKind)
{
RUNTIME_STUBS_HEADER(UpdateHClassForElementsKind);
JSHandle<JSTaggedValue> receiver = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the first parameter
JSTaggedType elementsKind = GetTArg(argv, argc, 1); // 1: means the first parameter
ElementsKind kind = Elements::FixElementsKind(static_cast<ElementsKind>(elementsKind));
auto arrayIndexMap = thread->GetArrayHClassIndexMap();
if (arrayIndexMap.find(kind) != arrayIndexMap.end()) {
auto index = thread->GetArrayHClassIndexMap().at(kind);
auto globalConst = thread->GlobalConstants();
auto targetHClassValue = globalConst->GetGlobalConstantObject(static_cast<size_t>(index));
auto hclass = JSHClass::Cast(targetHClassValue.GetTaggedObject());
JSHandle<JSObject>(receiver)->SetClass(hclass);
}
return JSTaggedValue::Hole().GetRawData();
}
void RuntimeStubs::DebugPrint(int fmtMessageId, ...)
{
std::string format = MessageString::GetMessageString(fmtMessageId);
@ -432,10 +449,10 @@ void RuntimeStubs::ProfileDefineClass(uintptr_t argGlue, uintptr_t func, int32_t
}
void RuntimeStubs::ProfileCreateObject(
uintptr_t argGlue, JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj)
uintptr_t argGlue, JSTaggedType func, int32_t offset, JSTaggedType newObj, int32_t traceId)
{
auto thread = JSThread::GlueToJSThread(argGlue);
thread->GetEcmaVM()->GetPGOProfiler()->ProfileCreateObject(func, offset, originObj, newObj);
thread->GetEcmaVM()->GetPGOProfiler()->ProfileCreateObject(func, offset, newObj, traceId);
}
void RuntimeStubs::ProfileObjLayout(uintptr_t argGlue, uintptr_t func, int32_t offset, uintptr_t object, int32_t store)

View File

@ -145,6 +145,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(NewEcmaHClass) \
V(UpdateLayOutAndAddTransition) \
V(CopyAndUpdateObjLayout) \
V(UpdateHClassForElementsKind) \
V(NoticeThroughChainAndRefreshUser) \
V(JumpToCInterpreter) \
V(StGlobalRecord) \
@ -356,7 +357,7 @@ public:
static void ProfileCall(uintptr_t argGlue, uintptr_t func, uintptr_t target, int32_t pcOffset, uint32_t incCount);
static void ProfileDefineClass(uintptr_t argGlue, uintptr_t func, int32_t offset, uintptr_t ctor);
static void ProfileCreateObject(
uintptr_t argGlue, JSTaggedType func, int32_t offset, JSTaggedType originObj, JSTaggedType newObj);
uintptr_t argGlue, JSTaggedType func, int32_t offset, JSTaggedType newObj, int32_t traceId);
static void ProfileOpType(uintptr_t argGlue, uintptr_t func, int32_t offset, int32_t type);
static void ProfileObjLayout(uintptr_t argGlue, uintptr_t func, int32_t offset, uintptr_t object, int32_t store);
static void FatalPrint(int fmtMessageId, ...);

View File

@ -876,7 +876,6 @@ HWTEST_F_L0(ObjectOperatorTest, Property_Add_002)
TaggedArray *resultArray = TaggedArray::Cast(handleObject1->GetElements().GetTaggedObject());
EXPECT_EQ(resultArray->Get(elementIndex).GetInt(), 3);
EXPECT_EQ(resultArray->GetLength(), 7U);
EXPECT_EQ(handleObject1->GetJSHClass()->GetElementRepresentation(), Representation::NONE);
// object is not DictionaryMode and not DefaultAttr
JSHandle<JSObject> handleObject2 = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
for (int i = 0; i< 4; i++) {