AOT supports ld/stobjbyname for function object

Issue: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8GEHD
Signed-off-by: weng-xi <wengxi1@huawei.com>
Change-Id: I81b970dd66b62700aaeed3b39806ce0a7d1d92d0
This commit is contained in:
weng-xi 2023-11-14 21:23:21 +08:00
parent 91b7756e39
commit 40e3828c68
37 changed files with 501 additions and 173 deletions

View File

@ -97,6 +97,8 @@ void MethodSnapshotInfo::StoreDataToGlobalData(EcmaVM *vm, const JSPandaFile *js
const std::set<uint32_t> &skippedMethods)
{
JSThread *thread = vm->GetJSThread();
ObjectFactory *factory = vm->GetFactory();
PGOTypeManager *ptManager = thread->GetCurrentEcmaContext()->GetPTManager();
for (auto item : info_) {
const ItemData &data = item.second;
JSHandle<ConstantPool> cp(thread,
@ -106,10 +108,20 @@ void MethodSnapshotInfo::StoreDataToGlobalData(EcmaVM *vm, const JSPandaFile *js
uint32_t snapshotCpArrIdx = globalData.GetCpArrIdxByConstanPoolId(data.constantPoolId_);
JSHandle<TaggedArray> snapshotCpArr(thread, globalData.GetCurSnapshotCpArray());
JSHandle<ConstantPool> snapshotCp(thread, snapshotCpArr->Get(snapshotCpArrIdx));
PGOTypeLocation loc(jsPandaFile, data.methodOffset_, data.bcIndex_);
ProfileType pt = ptManager->GetRootIdByLocation(loc);
JSHandle<JSTaggedValue> ihc = JSHandle<JSTaggedValue>(thread, ptManager->QueryHClass(pt, pt));
JSHandle<AOTLiteralInfo> aotLiteralInfo = factory->NewAOTLiteralInfo(1); // 1: only one method
aotLiteralInfo->SetObjectToCache(thread, 0, JSTaggedValue(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE));
if (!ihc->IsUndefined()) {
aotLiteralInfo->SetIhc(ihc.GetTaggedValue());
}
if (skippedMethods.find(methodOffset) == skippedMethods.end()) {
globalData.RecordReviseData(SnapshotReviseInfo::Type::METHOD,
BaseReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
snapshotCp->SetObjectToCache(thread, data.constantPoolIdx_, JSTaggedValue(methodOffset));
aotLiteralInfo->SetObjectToCache(thread, 0, JSTaggedValue(methodOffset));
snapshotCp->SetObjectToCache(thread, data.constantPoolIdx_, aotLiteralInfo.GetTaggedValue());
globalData.RecordReviseData(
ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
}
}
}
@ -140,8 +152,8 @@ void ClassLiteralSnapshotInfo::StoreDataToGlobalData(EcmaVM *vm, const JSPandaFi
JSHandle<JSTaggedValue> chc = JSHandle<JSTaggedValue>(thread, ptManager->QueryHClass(ctorPt, ctorPt));
CollectLiteralInfo(vm, arrayHandle, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
globalData.RecordReviseData(SnapshotReviseInfo::Type::LITERAL,
BaseReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
globalData.RecordReviseData(
ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
}
}
@ -174,8 +186,8 @@ void ObjectLiteralSnapshotInfo::StoreDataToGlobalData(EcmaVM *vm, const JSPandaF
JSHandle<JSTaggedValue> chc = JSHandle<JSTaggedValue>(thread, ptManager->QueryHClass(ctorPt, ctorPt));
CollectLiteralInfo(vm, properties, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
globalData.RecordReviseData(SnapshotReviseInfo::Type::LITERAL,
BaseReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
globalData.RecordReviseData(
ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
}
}
@ -198,8 +210,8 @@ void ArrayLiteralSnapshotInfo::StoreDataToGlobalData(EcmaVM *vm, const JSPandaFi
JSHandle<JSTaggedValue> ihc = thread->GlobalConstants()->GetHandledUndefined();
JSHandle<JSTaggedValue> chc = thread->GlobalConstants()->GetHandledUndefined();
CollectLiteralInfo(vm, literal, data.constantPoolIdx_, snapshotCp, skippedMethods, ihc, chc);
globalData.RecordReviseData(SnapshotReviseInfo::Type::LITERAL,
BaseReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
globalData.RecordReviseData(
ReviseData::ItemData {globalData.GetCurDataIdx(), snapshotCpArrIdx, data.constantPoolIdx_});
}
}

View File

@ -20,7 +20,7 @@
#include "ecmascript/tagged_array-inl.h"
namespace panda::ecmascript::kungfu {
JSHandle<ConstantPool> BaseReviseData::GetConstantPoolFromSnapshotData(JSThread *thread,
JSHandle<ConstantPool> ReviseData::GetConstantPoolFromSnapshotData(JSThread *thread,
const SnapshotGlobalData *globalData,
uint32_t dataIdx, uint32_t cpArrayIdx)
{
@ -29,27 +29,7 @@ JSHandle<ConstantPool> BaseReviseData::GetConstantPoolFromSnapshotData(JSThread
return JSHandle<ConstantPool>(thread, cpArr->Get(cpArrayIdx));
}
void MethodReviseData::Resolve(JSThread *thread, const SnapshotGlobalData *globalData,
const CMap<std::pair<std::string, uint32_t>, uint32_t> &methodToEntryIndexMap)
{
for (auto &item: data_) {
JSHandle<ConstantPool> newCP = GetConstantPoolFromSnapshotData(thread, globalData,
item.dataIdx_, item.cpArrayIdx_);
JSTaggedValue val = newCP->GetObjectFromCache(item.constpoolIdx_);
uint32_t methodOffset = static_cast<uint32_t>(val.GetInt());
if (thread->GetEcmaVM()->GetJSOptions().IsEnableCompilerLogSnapshot()) {
LOG_COMPILER(INFO) << "[aot-snapshot] store AOT entry index of method (offset: " << methodOffset << ") ";
}
std::string name = globalData->GetFileNameByDataIdx(item.dataIdx_).c_str();
AnFileInfo::FuncEntryIndexKey key = std::make_pair(name, methodOffset);
if (methodToEntryIndexMap.find(key) != methodToEntryIndexMap.end()) {
uint32_t entryIndex = methodToEntryIndexMap.at(key);
newCP->SetObjectToCache(thread, item.constpoolIdx_, JSTaggedValue(entryIndex));
}
}
}
void LiteralReviseData::Resolve(JSThread *thread, const SnapshotGlobalData *globalData,
void ReviseData::Resolve(JSThread *thread, const SnapshotGlobalData *globalData,
const CMap<std::pair<std::string, uint32_t>, uint32_t> &methodToEntryIndexMap)
{
for (auto &item: data_) {

View File

@ -25,11 +25,7 @@ class SnapshotGlobalData;
* The information that needs to be revised before saving the 'ai' file is recorded in SnapshotReviseData.
* Currently, the revised information includes the entry index of each method in the 'an' file.
*/
#define REVISE_DATA_TYPE_LIST(V) \
V(METHOD, Method) \
V(LITERAL, Literal)
class BaseReviseData {
class ReviseData {
public:
struct ItemData {
uint32_t dataIdx_;
@ -37,69 +33,42 @@ public:
int32_t constpoolIdx_;
};
BaseReviseData() = default;
virtual ~BaseReviseData() = default;
ReviseData() = default;
virtual ~ReviseData() = default;
void Record(ItemData data)
{
data_.emplace_back(data);
}
virtual void Resolve(JSThread *thread, const SnapshotGlobalData *globalData,
const CMap<std::pair<std::string, uint32_t>, uint32_t> &methodToEntryIndexMap) = 0;
void Resolve(JSThread *thread, const SnapshotGlobalData *globalData,
const CMap<std::pair<std::string, uint32_t>, uint32_t> &methodToEntryIndexMap);
protected:
JSHandle<ConstantPool> GetConstantPoolFromSnapshotData(JSThread *thread, const SnapshotGlobalData *globalData,
uint32_t dataIdx, uint32_t cpArrayIdx);
using ReviseData = std::vector<ItemData>;
ReviseData data_ {};
std::vector<ItemData> data_;
};
#define DEFINE_REVISE_CLASS(V, name) \
class name##ReviseData final : public BaseReviseData { \
public: \
virtual void Resolve(JSThread *thread, const SnapshotGlobalData *globalData, \
const CMap<std::pair<std::string, uint32_t>, uint32_t> &methodToEntryIndexMap) override; \
};
REVISE_DATA_TYPE_LIST(DEFINE_REVISE_CLASS)
#undef DEFINE_REVISE_CLASS
class SnapshotReviseInfo {
public:
enum class Type {
#define DEFINE_TYPE(type, ...) type,
REVISE_DATA_TYPE_LIST(DEFINE_TYPE)
#undef DEFINE_TYPE
};
SnapshotReviseInfo()
{
#define ADD_REVISE_DATA(V, name) \
reviseData_.emplace_back(std::make_unique<name##ReviseData>());
REVISE_DATA_TYPE_LIST(ADD_REVISE_DATA)
#undef ADD_REVISE_DATA
}
SnapshotReviseInfo() = default;
~SnapshotReviseInfo() = default;
void Record(Type type, BaseReviseData::ItemData data)
void Record(ReviseData::ItemData data)
{
size_t reviseDataIdx = static_cast<size_t>(type);
reviseData_.at(reviseDataIdx)->Record(data);
reviseData_.Record(data);
}
void ResolveData(JSThread *thread, const SnapshotGlobalData *globalData,
const CMap<std::pair<std::string, uint32_t>, uint32_t> &methodToEntryIndexMap)
{
for (auto &data : reviseData_) {
data->Resolve(thread, globalData, methodToEntryIndexMap);
}
reviseData_.Resolve(thread, globalData, methodToEntryIndexMap);
}
private:
CVector<std::unique_ptr<BaseReviseData>> reviseData_ {};
ReviseData reviseData_ {};
};
#undef REVISE_DATA_TYPE_LIST
class SnapshotGlobalData {
public:
@ -141,9 +110,9 @@ public:
CString GetFileNameByDataIdx(uint32_t dataIdx) const;
void RecordReviseData(SnapshotReviseInfo::Type type, BaseReviseData::ItemData data)
void RecordReviseData(ReviseData::ItemData data)
{
reviseInfo_.Record(type, data);
reviseInfo_.Record(data);
}
void ResolveSnapshotData(JSThread *thread,

View File

@ -462,6 +462,8 @@ namespace panda::ecmascript::kungfu {
#define ASM_INTERPRETER_BC_LAYOUT_PROFILER_STUB_LIST(V) \
APPEND_SUFFIX(HandleDefineclasswithbufferImm8Id16Id16Imm16V8, V) \
APPEND_SUFFIX_IMM16(HandleDefineclasswithbufferImm16Id16Id16Imm16V8, V) \
APPEND_SUFFIX(HandleDefinefuncImm8Id16Imm8, V) \
APPEND_SUFFIX_IMM16(HandleDefinefuncImm16Id16Imm8, V) \
APPEND_SUFFIX(HandleDefinegettersetterbyvalueV8V8V8V8, V) \
APPEND_SUFFIX(HandleCreateobjectwithbufferImm8Id16, V) \
APPEND_SUFFIX_IMM16(HandleCreateobjectwithbufferImm16Id16, V) \

View File

@ -438,6 +438,17 @@ public:
}
}
static bool IsDefineFunc(EcmaOpcode opcode)
{
switch (opcode) {
case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8:
case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8:
return true;
default:
return false;
}
}
private:
static uint8_t ReadByte(const uint8_t *pc)
{

View File

@ -697,9 +697,9 @@ GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, Ga
Bind(&cache);
{
if (type == ConstPoolType::METHOD) {
Label isInt(env_);
Branch(TaggedIsInt(*result), &isInt, &exit);
Bind(&isInt);
Label isAOTLiteralInfo(env_);
Branch(IsAOTLiteralInfo(*result), &isAOTLiteralInfo, &exit);
Bind(&isAOTLiteralInfo);
{
result = CallRuntime(glue, RTSTUB_ID(GetMethodFromCache), Gate::InvalidGateRef,
{ constPool, Int32ToTaggedInt(index), module }, hirGate);

View File

@ -4253,7 +4253,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm8Id16Imm8)
GateRef length = ReadInst8_3(pc);
DEFVARIABLE(result, VariableType::JS_POINTER(),
GetMethodFromConstPool(glue, constpool, GetModule(sp), ZExtInt16ToInt32(methodId)));
result = CallRuntime(glue, RTSTUB_ID(DefineFunc), { *result });
result = CallRuntime(glue, RTSTUB_ID(DefineFunc), { constpool, Int16ToTaggedInt(methodId), GetModule(sp) });
Label notException(env);
CHECK_EXCEPTION_WITH_JUMP(*result, &notException);
Bind(&notException);
@ -4266,6 +4266,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm8Id16Imm8)
SetLexicalEnvToFunction(glue, *result, envHandle);
GateRef currentFunc = GetFunctionFromFrame(frame);
SetHomeObjectToFunction(glue, *result, GetHomeObjectFromFunction(currentFunc));
callback.ProfileDefineClass(*result);
varAcc = *result;
DISPATCH_WITH_ACC(DEFINEFUNC_IMM8_ID16_IMM8);
}
@ -4279,7 +4280,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm16Id16Imm8)
GateRef length = ReadInst8_4(pc);
DEFVARIABLE(result, VariableType::JS_POINTER(),
GetMethodFromConstPool(glue, constpool, GetModule(sp), ZExtInt16ToInt32(methodId)));
result = CallRuntime(glue, RTSTUB_ID(DefineFunc), { *result });
result = CallRuntime(glue, RTSTUB_ID(DefineFunc), { constpool, Int16ToTaggedInt(methodId), GetModule(sp) });
Label notException(env);
CHECK_EXCEPTION_WITH_JUMP(*result, &notException);
Bind(&notException);
@ -4293,6 +4294,7 @@ DECLARE_ASM_HANDLER(HandleDefinefuncImm16Id16Imm8)
GateRef currentFunc = GetFunctionFromFrame(frame);
SetHomeObjectToFunction(glue, *result, GetHomeObjectFromFunction(currentFunc));
varAcc = *result;
callback.ProfileDefineClass(*result);
DISPATCH_WITH_ACC(DEFINEFUNC_IMM16_ID16_IMM8);
}
}

View File

@ -76,8 +76,9 @@ void PGOBCInfo::Record(const BytecodeInstruction &bcIns, int32_t bcIndex,
} else if (Bytecodes::IsCallOp(opcode)) {
Record(InfoDetail {recordName, methodOffset, bcIndex, bcOffset, 0}, Type::CALL_TARGET);
} else if (Bytecodes::IsDefineClassWithBufferOp(opcode)) {
auto cpIndex = bcIns.GetId().AsRawValue();
Record(InfoDetail {recordName, methodOffset, bcIndex, bcOffset, cpIndex}, Type::CLASS);
Record(InfoDetail {recordName, methodOffset, bcIndex, bcOffset, 0}, Type::CLASS);
} else if (Bytecodes::IsDefineFunc(opcode)) {
Record(InfoDetail {recordName, methodOffset, bcIndex, bcOffset, 0}, Type::FUNCTION);
}
}
} // namespace panda::ecmascript

View File

@ -28,10 +28,11 @@ public:
EMPTY_ARRAY,
CALL_TARGET,
CLASS,
FUNCTION,
TYPE_NUM,
TYPE_FIRST = OBJ_LITERAL,
TYPE_LAST = CLASS,
TYPE_LAST = FUNCTION,
};
struct InfoDetail {

View File

@ -130,6 +130,57 @@ void ObjectLiteralParser::GenerateHClass(const PGOHClassGenerator &generator, co
generator.GenerateHClass(rootSampleType);
}
bool FunctionParser::RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLocation &loc)
{
auto rootType = defType.GetProfileType();
auto ctorPt = defType.GetCtorPt();
if (ctorPt.IsNone()) {
return false;
}
PGOSampleType ctorSampleType(ctorPt);
auto protoPt = defType.GetProtoTypePt();
if (protoPt.IsNone()) {
return false;
}
PGOSampleType protoSampleType(protoPt);
ptManager_->RecordLocationToRootType(loc, rootType);
auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
ptManager_->RecordLocationToRootType(ctorLoc, ctorPt);
auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
ptManager_->RecordLocationToRootType(protoLoc, protoPt);
return true;
}
void FunctionParser::GenerateHClass(const PGOHClassGenerator &generator, const PGOTypeLocation &loc)
{
auto thread = ptManager_->GetJSThread();
[[maybe_unused]] EcmaHandleScope scope(thread);
auto rootType = ptManager_->GetRootIdByLocation(loc);
PGOSampleType iSampleType(rootType);
auto ctorLoc = loc.ChangeType(PGOTypeLocation::Type::CONSTRUCTOR);
auto ctorPt = ptManager_->GetRootIdByLocation(ctorLoc);
PGOSampleType ctorSampleType(ctorPt);
auto protoLoc = loc.ChangeType(PGOTypeLocation::Type::PROTOTYPE);
auto protoPt = ptManager_->GetRootIdByLocation(protoLoc);
PGOSampleType protoSampleType(protoPt);
// testcase: propertyaccessor2.ts. protoSampleType not find desc
if (generator.FindHClassLayoutDesc(ctorSampleType) && generator.FindHClassLayoutDesc(protoSampleType)) {
generator.GenerateHClass(protoSampleType);
auto phValue = ptManager_->QueryHClass(protoPt, protoPt);
JSHandle<JSHClass> phclass(thread, phValue);
JSHandle<JSObject> prototype = thread->GetEcmaVM()->GetFactory()->NewJSObject(phclass);
generator.GenerateIHClass(iSampleType, prototype);
}
}
PGOTypeParser::PGOTypeParser(const PGOProfilerDecoder &decoder, PGOTypeManager *ptManager)
: decoder_(decoder), ptManager_(ptManager)
{
@ -137,6 +188,7 @@ PGOTypeParser::PGOTypeParser(const PGOProfilerDecoder &decoder, PGOTypeManager *
parsers_.emplace_back(std::make_unique<EmptyArrayParser>(ptManager));
parsers_.emplace_back(std::make_unique<ArrayLiteralParser>(ptManager));
parsers_.emplace_back(std::make_unique<ObjectLiteralParser>(ptManager));
parsers_.emplace_back(std::make_unique<FunctionParser>(ptManager));
}
void PGOTypeParser::CreatePGOType(BytecodeInfoCollector &collector)

View File

@ -77,6 +77,14 @@ private:
virtual void GenerateHClass(const PGOHClassGenerator &generator, const PGOTypeLocation &loc) override;
};
class FunctionParser final : public BaseParser {
public:
FunctionParser(PGOTypeManager *ptManager) : BaseParser(ptManager, PGOBCInfo::Type::FUNCTION) {}
private:
virtual bool RecordTypeInfo(const PGODefineOpType &defType, const PGOTypeLocation &loc) override;
virtual void GenerateHClass(const PGOHClassGenerator &generator, const PGOTypeLocation &loc) override;
};
class PGOTypeParser {
public:
explicit PGOTypeParser(const PGOProfilerDecoder &decoder, PGOTypeManager *ptManager);

View File

@ -2504,14 +2504,16 @@ void SlowPathLowering::LowerDefineClassWithBuffer(GateRef gate)
void SlowPathLowering::LowerDefineFunc(GateRef gate)
{
GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
GateRef methodId = builder_.TruncInt64ToInt32(acc_.GetValueIn(gate, 0));
GateRef methodId = acc_.GetValueIn(gate, 0);
GateRef length = acc_.GetValueIn(gate, 1);
auto method = builder_.GetObjectFromConstPool(glue_, gate, jsFunc, methodId, ConstPoolType::METHOD);
GateRef constPool = builder_.GetConstPoolFromFunction(jsFunc);
GateRef module = builder_.GetModuleFromFunction(jsFunc);
Label defaultLabel(&builder_);
Label successExit(&builder_);
Label exceptionExit(&builder_);
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(DefineFunc), { method });
GateRef result = LowerCallRuntime(gate, RTSTUB_ID(DefineFunc),
{ constPool, builder_.ToTaggedInt(methodId), module });
builder_.Branch(builder_.TaggedIsException(result), &exceptionExit, &defaultLabel);
builder_.Bind(&defaultLabel);
{

View File

@ -524,6 +524,37 @@ static void DumpPropertyKey(JSTaggedValue key, std::ostream &os)
}
}
static void DumpAttr(const PropertyAttributes &attr, bool fastMode, std::ostream &os)
{
if (attr.IsAccessor()) {
os << "(Accessor) ";
}
os << "Attr(";
if (attr.IsNoneAttributes()) {
os << "NONE";
}
if (attr.IsWritable()) {
os << "W";
}
if (attr.IsEnumerable()) {
os << "E";
}
if (attr.IsConfigurable()) {
os << "C";
}
os << ")";
os << " InlinedProps: " << attr.IsInlinedProps();
if (fastMode) {
os << " Order: " << std::dec << attr.GetOffset();
os << " SortedIndex: " << std::dec << attr.GetSortedIndex();
} else {
os << " Order: " << std::dec << attr.GetDictionaryOrder();
}
}
static void DumpHClass(const JSHClass *jshclass, std::ostream &os, bool withDetail)
{
DISALLOW_GARBAGE_COLLECTION;
@ -538,8 +569,18 @@ static void DumpHClass(const JSHClass *jshclass, std::ostream &os, bool withDeta
attrs.DumpTaggedValue(os);
os << "\n";
if (withDetail && !attrs.IsNull()) {
LayoutInfo *layoutInfo = LayoutInfo::Cast(attrs.GetTaggedObject());
layoutInfo->Dump(os);
LayoutInfo *layout = LayoutInfo::Cast(jshclass->GetLayout().GetTaggedObject());
int element = static_cast<int>(jshclass->NumberOfProps());
for (int i = 0; i < element; i++) {
JSTaggedValue key = layout->GetKey(i);
PropertyAttributes attr = layout->GetAttr(i);
os << std::right << std::setw(DUMP_PROPERTY_OFFSET);
os << "[" << i << "]: ";
DumpPropertyKey(key, os);
os << " : ";
DumpAttr(attr, true, os);
os << "\n";
}
}
os << " - Transitions :" << std::setw(DUMP_TYPE_OFFSET);
@ -609,37 +650,6 @@ static void DumpClass(TaggedObject *obj, std::ostream &os)
DumpHClass(JSHClass::Cast(obj), os, true);
}
static void DumpAttr(const PropertyAttributes &attr, bool fastMode, std::ostream &os)
{
if (attr.IsAccessor()) {
os << "(Accessor) ";
}
os << "Attr(";
if (attr.IsNoneAttributes()) {
os << "NONE";
}
if (attr.IsWritable()) {
os << "W";
}
if (attr.IsEnumerable()) {
os << "E";
}
if (attr.IsConfigurable()) {
os << "C";
}
os << ")";
os << " InlinedProps: " << attr.IsInlinedProps();
if (fastMode) {
os << " Order: " << std::dec << attr.GetOffset();
os << " SortedIndex: " << std::dec << attr.GetSortedIndex();
} else {
os << " Order: " << std::dec << attr.GetDictionaryOrder();
}
}
static void DumpObject(TaggedObject *obj, std::ostream &os)
{
DISALLOW_GARBAGE_COLLECTION;

View File

@ -42,6 +42,12 @@ void ICRuntime::UpdateLoadHandler(const ObjectOperator &op, JSHandle<JSTaggedVal
}
JSHandle<JSTaggedValue> handlerValue;
JSHandle<JSHClass> hclass(GetThread(), receiver->GetTaggedObject()->GetClass());
// When a transition occurs without the shadow property, AOT does not trigger the
// notifyprototypechange behavior, so for the case where the property does not
// exist and the Hclass is AOT, IC needs to be abandoned.
if (hclass->IsTS() && !op.IsFound()) {
return;
}
if (op.IsElement()) {
if (!op.IsFound() && hclass->IsDictionaryElement()) {
return;
@ -201,7 +207,6 @@ JSTaggedValue LoadICRuntime::LoadValueMiss(JSHandle<JSTaggedValue> receiver, JSH
icAccessor_.SetAsMega();
return result.GetTaggedValue();
}
UpdateLoadHandler(op, key, receiver);
}

View File

@ -4854,13 +4854,10 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
uint16_t methodId = READ_INST_16_1();
uint16_t length = READ_INST_8_3();
LOG_INST() << "intrinsics::definefunc length: " << length;
auto constpool = GetConstantPool(sp);
auto module = GetEcmaModule(sp);
Method *method = Method::Cast(GET_METHOD_FROM_CACHE(methodId).GetTaggedObject());
ASSERT(method != nullptr);
auto res = SlowRuntimeStub::DefineFunc(thread, method);
auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, module);
JSFunction *jsFunc = JSFunction::Cast(res.GetTaggedObject());
jsFunc->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length));
@ -4881,10 +4878,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, const uint8_t
auto constpool = GetConstantPool(sp);
auto module = GetEcmaModule(sp);
Method *method = Method::Cast(GET_METHOD_FROM_CACHE(methodId).GetTaggedObject());
ASSERT(method != nullptr);
auto res = SlowRuntimeStub::DefineFunc(thread, method);
auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, module);
JSFunction *jsFunc = JSFunction::Cast(res.GetTaggedObject());
jsFunc->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length));

View File

@ -6644,11 +6644,7 @@ void InterpreterAssembly::HandleDefinefuncImm16Id16Imm8(
LOG_INST() << "intrinsics::definefunc length: " << length;
constpool = GetConstantPool(sp);
Method *method =
Method::Cast(ConstantPool::GetMethodFromCache(thread, constpool, GetModule(sp), methodId).GetTaggedObject());
ASSERT(method != nullptr);
auto res = SlowRuntimeStub::DefineFunc(thread, method);
auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, GetModule(sp));
JSFunction *jsFunc = JSFunction::Cast(res.GetTaggedObject());
jsFunc->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length));
@ -6671,12 +6667,9 @@ void InterpreterAssembly::HandleDefinefuncImm8Id16Imm8(
uint16_t methodId = READ_INST_16_1();
uint16_t length = READ_INST_8_3();
LOG_INST() << "intrinsics::definefunc length: " << length;
constpool = GetConstantPool(sp);
Method *method =
Method::Cast(ConstantPool::GetMethodFromCache(thread, constpool, GetModule(sp), methodId).GetTaggedObject());
ASSERT(method != nullptr);
auto res = SlowRuntimeStub::DefineFunc(thread, method);
constpool = GetConstantPool(sp);
auto res = SlowRuntimeStub::DefineFunc(thread, constpool, methodId, GetModule(sp));
JSFunction *jsFunc = JSFunction::Cast(res.GetTaggedObject());
jsFunc->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length));

View File

@ -965,12 +965,14 @@ JSTaggedValue SlowRuntimeStub::StArraySpread(JSThread *thread, JSTaggedValue dst
return RuntimeStubs::RuntimeStArraySpread(thread, dstHandle, index, srcHandle);
}
JSTaggedValue SlowRuntimeStub::DefineFunc(JSThread *thread, Method *method)
JSTaggedValue SlowRuntimeStub::DefineFunc(JSThread *thread, JSTaggedValue constPool, uint16_t methodId,
JSTaggedValue module)
{
INTERPRETER_TRACE(thread, DefineFunc);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<Method> methodHandle(thread, method);
return RuntimeStubs::RuntimeDefinefunc(thread, methodHandle);
JSHandle<JSTaggedValue> constpoolHandle(thread, constPool);
JSHandle<JSTaggedValue> moduleHandle(thread, module);
return RuntimeStubs::RuntimeDefinefunc(thread, constpoolHandle, methodId, moduleHandle);
}
JSTaggedValue SlowRuntimeStub::GetSuperConstructor(JSThread *thread, JSTaggedValue ctor)

View File

@ -142,7 +142,7 @@ public:
static JSTaggedValue TryUpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value);
static JSTaggedValue StArraySpread(JSThread *thread, JSTaggedValue dst, JSTaggedValue index, JSTaggedValue src);
static JSTaggedValue DefineFunc(JSThread *thread, Method *method);
static JSTaggedValue DefineFunc(JSThread *thread, JSTaggedValue constPool, uint16_t methodId, JSTaggedValue module);
static JSTaggedValue GetSuperConstructor(JSThread *thread, JSTaggedValue ctor);
static JSTaggedValue SuperCall(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget, uint16_t firstVRegIdx,

View File

@ -104,6 +104,10 @@ JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandl
JSHandle<JSTaggedValue> proto;
if (!fun->HasFunctionPrototype()) {
proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, fun));
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(fun.GetTaggedType(),
JSTaggedType(proto->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
}
} else {
proto = JSHandle<JSTaggedValue>(thread, fun->GetProtoOrHClass());
}
@ -112,7 +116,7 @@ JSHClass *JSFunction::GetOrCreateInitialJSHClass(JSThread *thread, const JSHandl
JSHandle<JSHClass> hclass = factory->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, proto);
fun->SetProtoOrHClass(thread, hclass);
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileDefineIClass(fun.GetTaggedType(), hclass.GetTaggedType());
thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(fun.GetTaggedType(), hclass.GetTaggedType());
}
return *hclass;
}
@ -121,7 +125,11 @@ JSTaggedValue JSFunction::PrototypeGetter(JSThread *thread, const JSHandle<JSObj
{
JSHandle<JSFunction> func = JSHandle<JSFunction>::Cast(self);
if (!func->HasFunctionPrototype()) {
NewJSFunctionPrototype(thread, func);
JSHandle<JSTaggedValue> proto = JSHandle<JSTaggedValue>::Cast(NewJSFunctionPrototype(thread, func));
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(func.GetTaggedType(),
JSTaggedType(proto->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
}
}
return JSFunction::Cast(*self)->GetFunctionPrototype();
}
@ -141,6 +149,10 @@ bool JSFunction::PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &sel
func->SetProtoOrHClass(thread, newClass);
} else {
func->SetFunctionPrototype(thread, value.GetTaggedValue());
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(func.GetTaggedType(),
JSTaggedType(value->GetTaggedObject()->GetClass()), pgo::ProfileType::Kind::PrototypeId);
}
}
return true;
}
@ -716,7 +728,7 @@ JSHandle<JSHClass> JSFunction::GetOrCreateDerivedJSHClass(JSThread *thread, JSHa
derived->SetProtoOrHClass(thread, newJSHClass);
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileDefineIClass(derived.GetTaggedType(),
thread->GetEcmaVM()->GetPGOProfiler()->ProfileClassRootHClass(derived.GetTaggedType(),
newJSHClass.GetTaggedType());
}

View File

@ -223,8 +223,9 @@ public:
bool isLoadedAOT = jsPandaFile->IsLoadedAOT();
bool hasEntryIndex = false;
uint32_t entryIndex = 0;
if (isLoadedAOT && val.IsInt()) {
entryIndex = static_cast<uint32_t>(val.GetInt());
if (isLoadedAOT && val.IsAOTLiteralInfo()) {
JSHandle<AOTLiteralInfo> entryIndexes(thread, val);
entryIndex = static_cast<uint32_t>(entryIndexes->GetObjectFromCache(0).GetInt()); // 0: only one method
hasEntryIndex = true;
val = JSTaggedValue::Hole();
}

View File

@ -96,7 +96,7 @@ void PGOProfiler::ProfileDefineClass(JSTaggedType ctor)
}
}
void PGOProfiler::ProfileDefineIClass(JSTaggedType ctor, JSTaggedType ihcValue)
void PGOProfiler::ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcValue, ProfileType::Kind kind)
{
if (!isEnable_) {
return;
@ -114,11 +114,11 @@ void PGOProfiler::ProfileDefineIClass(JSTaggedType ctor, JSTaggedType ihcValue)
auto ctorMethod = Method::Cast(ctorMethodValue);
auto entityId = ctorMethod->GetMethodId().GetOffset();
auto ihc = JSHClass::Cast(JSTaggedValue(ihcValue).GetTaggedObject());
ihc->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
if (GetProfileType(ihcValue, ihcValue).IsNone()) {
ProfileType ihcProfileType(GetMethodAbcId(ctorFunc), entityId, ProfileType::Kind::ClassId, true);
InsertProfileType(ihcValue, ihcValue, ihcProfileType);
auto rootHc = JSHClass::Cast(JSTaggedValue(rootHcValue).GetTaggedObject());
rootHc->SetParent(vm_->GetJSThread(), JSTaggedValue::Undefined());
if (GetProfileType(rootHcValue, rootHcValue).IsNone()) {
ProfileType ihcProfileType(GetMethodAbcId(ctorFunc), entityId, kind, true);
InsertProfileType(rootHcValue, rootHcValue, ihcProfileType);
}
}
@ -605,6 +605,16 @@ void PGOProfiler::ProfileBytecode(ApEntityId abcId, const CString &recordName, J
DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8: {
uint8_t slotId = READ_INST_8_0();
DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8: {
uint16_t slotId = READ_INST_16_0();
DumpDefineClass(abcId, recordName, methodId, bcOffset, slotId, profileTypeInfo);
break;
}
case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
case EcmaOpcode::CREATEEMPTYARRAY_IMM8: {
@ -971,12 +981,14 @@ void PGOProfiler::DumpDefineClass(ApEntityId abcId, const CString &recordName, E
objDefType.SetCtorPt(ctorType);
recordInfos_->AddRootLayout(ctorRootHClass, ctorType);
if (protoOrHClass.IsJSObject()) {
auto prototypeObj = JSObject::Cast(protoOrHClass);
auto prototypeHClass = prototypeObj->GetClass();
auto prototypeRootHClass = JSTaggedType(JSHClass::FindRootHClass(prototypeHClass));
auto prototypeType = GetProfileType(prototypeRootHClass, prototypeRootHClass);
objDefType.SetProtoTypePt(prototypeType);
recordInfos_->AddRootLayout(prototypeRootHClass, prototypeType);
}
recordInfos_->AddDefine(recordType, methodId, bcOffset, objDefType);
}

View File

@ -60,7 +60,8 @@ public:
void ProfileDefineClass(JSTaggedType ctor);
void ProfileDefineGetterSetter(
JSHClass *receverHClass, JSHClass *holderHClass, const JSHandle<JSTaggedValue> &func, int32_t pcOffset);
void ProfileDefineIClass(JSTaggedType ctor, JSTaggedType ihcValue);
void ProfileClassRootHClass(JSTaggedType ctor, JSTaggedType rootHcValue,
ProfileType::Kind kind = ProfileType::Kind::ClassId);
void UpdateProfileType(JSHClass *oldHClass, JSHClass *newHClass);
void SetSaveTimestamp(std::chrono::system_clock::time_point timestamp)

View File

@ -1877,10 +1877,36 @@ JSTaggedValue RuntimeStubs::RuntimeNewObjRange(JSThread *thread, const JSHandle<
return tagged;
}
JSTaggedValue RuntimeStubs::RuntimeDefinefunc(JSThread *thread, const JSHandle<Method> &methodHandle)
JSTaggedValue RuntimeStubs::RuntimeDefinefunc(JSThread *thread, const JSHandle<JSTaggedValue> &constpool,
uint16_t methodId, const JSHandle<JSTaggedValue> &module)
{
JSHandle<ConstantPool> constpoolHandle = JSHandle<ConstantPool>::Cast(constpool);
JSMutableHandle<JSTaggedValue> ihc(thread, JSTaggedValue::Undefined());
JSTaggedValue val = constpoolHandle->GetObjectFromCache(methodId);
if (val.IsAOTLiteralInfo()) {
JSHandle<AOTLiteralInfo> aotLiteralInfo(thread, val);
ihc.Update(aotLiteralInfo->GetIhc());
}
JSTaggedValue method = ConstantPool::GetMethodFromCache(thread, constpool.GetTaggedValue(),
module.GetTaggedValue(), methodId);
const JSHandle<Method> methodHandle(thread, method);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
return factory->NewJSFunction(methodHandle).GetTaggedValue();
JSHandle<JSFunction> result = factory->NewJSFunction(methodHandle);
if (!ihc->IsUndefined()) {
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> parentPrototype = env->GetObjectFunctionPrototype();
result->SetProtoOrHClass(thread, ihc);
JSHandle<JSObject> clsPrototype(thread, result->GetFunctionPrototype());
clsPrototype->GetClass()->SetPrototype(thread, parentPrototype);
JSHClass::EnableProtoChangeMarker(thread,
JSHandle<JSHClass>(thread, result->GetFunctionPrototype().GetTaggedObject()->GetClass()));
}
if (thread->GetEcmaVM()->IsEnablePGOProfiler()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileDefineClass(result.GetTaggedValue().GetRawData());
}
return result.GetTaggedValue();
}
JSTaggedValue RuntimeStubs::RuntimeCreateRegExpWithLiteral(JSThread *thread,
@ -2670,11 +2696,32 @@ JSTaggedValue RuntimeStubs::RuntimeNotifyConcurrentResult(JSThread *thread, JSTa
return JSTaggedValue::Undefined();
}
bool RuntimeStubs::IsNeedNotifyHclassChangedForAotTransition(JSThread *thread, const JSHandle<JSHClass> &hclass,
JSTaggedValue key)
{
JSMutableHandle<JSObject> protoHandle(thread, hclass->GetPrototype());
while (true) {
if (!protoHandle.GetTaggedValue().IsHeapObject()) {
break;
}
JSHClass *protoHclass = protoHandle->GetJSHClass();
if (JSHClass::FindPropertyEntry(thread, protoHclass, key) != -1) {
return true;
}
protoHandle.Update(protoHclass->GetPrototype());
}
return false;
}
JSTaggedValue RuntimeStubs::RuntimeUpdateHClass(JSThread *thread,
const JSHandle<JSHClass> &oldhclass, const JSHandle<JSHClass> &newhclass, JSTaggedValue key)
{
#if ECMASCRIPT_ENABLE_IC
if (IsNeedNotifyHclassChangedForAotTransition(thread, oldhclass, key)) {
JSHClass::NotifyHclassChanged(thread, oldhclass, newhclass, key);
}
JSHClass::EnablePHCProtoChangeMarker(thread, newhclass);
JSHClass::RefreshUsers(thread, oldhclass, newhclass);
#endif
return JSTaggedValue::Undefined();
}

View File

@ -1890,8 +1890,10 @@ DEF_RUNTIME_STUBS(NewObjRange)
DEF_RUNTIME_STUBS(DefineFunc)
{
RUNTIME_STUBS_HEADER(DefineFunc);
JSHandle<Method> method = GetHArg<Method>(argv, argc, 0); // 0: means the zeroth parameter
return RuntimeDefinefunc(thread, method).GetRawData();
JSHandle<JSTaggedValue> constpool = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
JSTaggedValue methodId = GetArg(argv, argc, 1); // 1: means the first parameter
JSHandle<JSTaggedValue> module = GetHArg<JSTaggedValue>(argv, argc, 2); // 2: means the second parameter
return RuntimeDefinefunc(thread, constpool, static_cast<uint16_t>(methodId.GetInt()), module).GetRawData();
}
DEF_RUNTIME_STUBS(CreateRegExpWithLiteral)

View File

@ -646,7 +646,8 @@ private:
static inline JSTaggedValue RuntimeNewObjRange(JSThread *thread, const JSHandle<JSTaggedValue> &func,
const JSHandle<JSTaggedValue> &newTarget, uint16_t firstArgIdx,
uint16_t length);
static inline JSTaggedValue RuntimeDefinefunc(JSThread *thread, const JSHandle<Method> &methodHandle);
static inline JSTaggedValue RuntimeDefinefunc(JSThread *thread, const JSHandle<JSTaggedValue> &constpool,
uint16_t methodId, const JSHandle<JSTaggedValue> &module);
static inline JSTaggedValue RuntimeCreateRegExpWithLiteral(JSThread *thread, const JSHandle<JSTaggedValue> &pattern,
uint8_t flags);
static inline JSTaggedValue RuntimeThrowIfSuperNotCorrectCall(JSThread *thread, uint16_t index,
@ -724,6 +725,8 @@ private:
const JSHandle<JSTaggedValue> &value);
static inline JSTaggedValue RuntimeNotifyConcurrentResult(JSThread *thread, JSTaggedValue result,
JSTaggedValue hint);
static inline bool IsNeedNotifyHclassChangedForAotTransition(JSThread *thread, const JSHandle<JSHClass> &hclass,
JSTaggedValue key);
static inline JSTaggedValue RuntimeUpdateHClass(JSThread *thread, const JSHandle<JSHClass> &oldhclass,
const JSHandle<JSHClass> &newhclass, JSTaggedValue key);
static inline JSTaggedValue RuntimeNotifyDebuggerStatement(JSThread *thread);

View File

@ -187,6 +187,8 @@ group("ark_aot_ts_test") {
"pgo_forof_set",
"pgo_forof_string",
"pgo_forof_typed_array",
"pgo_function_operation",
"pgo_function_prototype",
"pgo_objectliteral_operation",
"pgo_call_deopt",
"poplexenv",

View File

@ -13,3 +13,4 @@
5
5
foo

View File

@ -94,3 +94,9 @@ function getPrototypeOf(a)
getPrototypeOf(A);
getPrototypeOf(B);
A.prototype.foo = function() {
print("foo");
}
a.foo();

View File

@ -13,3 +13,4 @@
5
5
foo

View File

@ -0,0 +1,20 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("pgo_function_operation") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
}

View File

@ -0,0 +1,21 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
1
2
foo
bar
undefined
bar
1
1

View File

@ -0,0 +1,21 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
1
2
foo
bar
undefined
bar
1
1

View File

@ -0,0 +1,61 @@
/*
* 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.
*/
declare function print(arg:any):string;
function A() {
this.x = 1;
}
A.prototype.foo = function() {
print("foo");
}
A.prototype.bar = function() {
print("bar");
}
let a = new A();
print(a.x);
a.x =2;
print(a.x);
a.foo();
a.bar();
function B() {
this.x = 1;
}
function foo(b) {
print(b.bar);
}
let b = new B();
foo(b);
B.prototype.bar = "bar";
foo(b);
for(let i = 0; i<2; ++i) {
function C() {
this.x = 1;
}
let c = new C();
print(c.x);
}

View File

@ -0,0 +1,20 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/test/test_helper.gni")
host_aot_test_action("pgo_function_prototype") {
deps = []
is_only_typed_path = true
is_enable_pgo = true
}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
1

View File

@ -0,0 +1,14 @@
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
1

View File

@ -0,0 +1,25 @@
/*
* 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.
*/
declare function print(arg:any):string;
function B() {
this.x = 1;
}
B.prototype = {}
let b = new B();
print(b.x);