optimize asm interpreter performance

Description:
1. add runtime stat scope to get the data of time-consuming-points
2. use stub to impl these runtime time-consuming-points
Issue:https://gitee.com/openharmony/ark_js_runtime/issues/I552ZB?from=project-issue

Signed-off-by: zhangyukun <zhangyukun8@huawei.com>
Change-Id: I242b3ef8b4235d952aa32fda0d3d5b8ed2f8f776
This commit is contained in:
zhangyukun 2022-04-28 09:16:30 +08:00
parent c6cdb9b0c5
commit 35db7bf019
15 changed files with 318 additions and 25 deletions

View File

@ -53,7 +53,7 @@ JSTaggedValue BuiltinsSharedArrayBuffer::SharedArrayBufferConstructor(EcmaRuntim
JSTaggedValue BuiltinsSharedArrayBuffer::IsSharedArrayBuffer(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
BUILTINS_API_TRACE(thread, SharedArrayBuffer, IsSharedArrayBuffer);
BUILTINS_API_TRACE(argv->GetThread(), SharedArrayBuffer, IsSharedArrayBuffer);
[[maybe_unused]] EcmaHandleScope handleScope(argv->GetThread());
JSHandle<JSTaggedValue> arg = GetCallArg(argv, 0);
// 1. If Type(arg) is not Object,and it not has an [[ArrayBufferData]] internal slot return false.

View File

@ -646,6 +646,34 @@ DEF_CALL_SIGNATURE(ResumeRspAndReturn)
callSign->SetCallConv(CallSignature::CallConv::GHCCallConv);
}
DEF_CALL_SIGNATURE(StringsAreEquals)
{
// 2 : 2 input parameters
CallSignature stringsAreEquals("StringsAreEquals", 0, 2,
ArgumentsOrder::DEFAULT_ORDER, VariableType::BOOL());
*callSign = stringsAreEquals;
std::array<VariableType, 2> params = { // 2 : 2 input parameters
VariableType::JS_POINTER(),
VariableType::JS_POINTER(),
};
callSign->SetParameters(params.data());
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB);
}
DEF_CALL_SIGNATURE(BigIntEquals)
{
// 2 : 2 input parameters
CallSignature bigIntEquals("BigIntEquals", 0, 2,
ArgumentsOrder::DEFAULT_ORDER, VariableType::BOOL());
*callSign = bigIntEquals;
std::array<VariableType, 2> params = { // 2 : 2 input parameters
VariableType::JS_POINTER(),
VariableType::JS_POINTER(),
};
callSign->SetParameters(params.data());
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB);
}
#define PUSH_CALL_ARGS_AND_DISPATCH_SIGNATURE(name) \
/* 2 : 2 input parameters */ \
CallSignature signature(#name, 0, 2, \

View File

@ -298,6 +298,8 @@ private:
V(PushCallIThisRangeAndDispatchSlowPath)\
V(ResumeRspAndDispatch) \
V(ResumeRspAndReturn) \
V(StringsAreEquals) \
V(BigIntEquals) \
V(DebugPrint) \
V(FatalPrint) \
V(InsertOldToNewRSet) \

View File

@ -1937,23 +1937,55 @@ DECLARE_ASM_HANDLER(HandleInstanceOfDynPrefV8)
DECLARE_ASM_HANDLER(HandleStrictNotEqDynPrefV8)
{
auto env = GetEnvironment();
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
GateRef v0 = ReadInst8_1(pc);
GateRef left = GetVregValue(sp, ZExtInt8ToPtr(v0));
GateRef result = CallRuntime(glue, RTSTUB_ID(FastStrictNotEqual), { left, acc });
varAcc = result;
Label strictEqual(env);
Label notStrictEqual(env);
Label dispatch(env);
Branch(FastStrictEqual(glue, left, acc), &strictEqual, &notStrictEqual);
Bind(&strictEqual);
{
varAcc = ChangeInt64ToTagged(Int64(JSTaggedValue::VALUE_FALSE));
Jump(&dispatch);
}
Bind(&notStrictEqual);
{
varAcc = ChangeInt64ToTagged(Int64(JSTaggedValue::VALUE_TRUE));
Jump(&dispatch);
}
Bind(&dispatch);
DISPATCH_WITH_ACC(PREF_V8);
}
DECLARE_ASM_HANDLER(HandleStrictEqDynPrefV8)
{
auto env = GetEnvironment();
DEFVARIABLE(varAcc, VariableType::JS_ANY(), acc);
GateRef v0 = ReadInst8_1(pc);
GateRef left = GetVregValue(sp, ZExtInt8ToPtr(v0));
GateRef result = CallRuntime(glue, RTSTUB_ID(FastStrictEqual), { left, acc }); // acc is right
varAcc = result;
Label strictEqual(env);
Label notStrictEqual(env);
Label dispatch(env);
Branch(FastStrictEqual(glue, left, acc), &strictEqual, &notStrictEqual);
Bind(&strictEqual);
{
varAcc = ChangeInt64ToTagged(Int64(JSTaggedValue::VALUE_TRUE));
Jump(&dispatch);
}
Bind(&notStrictEqual);
{
varAcc = ChangeInt64ToTagged(Int64(JSTaggedValue::VALUE_FALSE));
Jump(&dispatch);
}
Bind(&dispatch);
DISPATCH_WITH_ACC(PREF_V8);
}

View File

@ -526,8 +526,7 @@ GateRef Stub::FindEntryFromNameDictionary(GateRef glue, GateRef elements, GateRe
Branch(IsString(key), &isString, &notString);
Bind(&isString);
{
hash = TruncInt64ToInt32(ChangeTaggedPointerToInt64(CallRuntime(glue,
RTSTUB_ID(StringGetHashCode), { key })));
hash = GetHashcodeFromString(glue, key);
Jump(&beforeDefineHash);
}
Bind(&notString);
@ -637,9 +636,7 @@ GateRef Stub::FindEntryFromTransitionDictionary(GateRef glue, GateRef elements,
Branch(IsString(key), &isString, &notString);
Bind(&isString);
{
hash = TruncInt64ToInt32(ChangeTaggedPointerToInt64(CallRuntime(glue,
RTSTUB_ID(StringGetHashCode),
{ key })));
hash = GetHashcodeFromString(glue, key);
Jump(&beforeDefineHash);
}
Bind(&notString);
@ -1244,6 +1241,27 @@ GateRef Stub::TaggedIsStringOrSymbol(GateRef obj)
return ret;
}
GateRef Stub::TaggedIsBigInt(GateRef obj)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
DEFVARIABLE(result, VariableType::BOOL(), False());
Label isHeapObject(env);
Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit);
Bind(&isHeapObject);
{
result = Int32Equal(GetObjectType(LoadHClass(obj)),
Int32(static_cast<int32_t>(JSType::BIGINT)));
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef Stub::IsUtf16String(GateRef string)
{
// compressedStringsEnabled fixed to true constant
@ -3019,6 +3037,122 @@ GateRef Stub::FastTypeOf(GateRef glue, GateRef obj)
return ret;
}
GateRef Stub::FastStrictEqual(GateRef glue, GateRef left, GateRef right)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
DEFVARIABLE(result, VariableType::BOOL(), False());
Label strictEqual(env);
Label leftIsNumber(env);
Label leftIsNotNumber(env);
Label sameVariableCheck(env);
Label stringEqualCheck(env);
Label stringCompare(env);
Label bigIntEqualCheck(env);
Label exit(env);
Branch(TaggedIsNumber(left), &leftIsNumber, &leftIsNotNumber);
Bind(&leftIsNumber);
{
Label rightIsNumber(env);
Branch(TaggedIsNumber(right), &rightIsNumber, &exit);
Bind(&rightIsNumber);
{
DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0.0));
DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0.0));
Label leftIsInt(env);
Label leftNotInt(env);
Label getRight(env);
Label numberEqualCheck(env);
Branch(TaggedIsInt(left), &leftIsInt, &leftNotInt);
Bind(&leftIsInt);
{
doubleLeft = ChangeInt32ToFloat64(TaggedCastToInt32(left));
Jump(&getRight);
}
Bind(&leftNotInt);
{
doubleLeft = TaggedCastToDouble(left);
Jump(&getRight);
}
Bind(&getRight);
{
Label rightIsInt(env);
Label rightNotInt(env);
Branch(TaggedIsInt(right), &rightIsInt, &rightNotInt);
Bind(&rightIsInt);
{
doubleRight = ChangeInt32ToFloat64(TaggedCastToInt32(right));
Jump(&numberEqualCheck);
}
Bind(&rightNotInt);
{
doubleRight = TaggedCastToDouble(right);
Jump(&numberEqualCheck);
}
}
Bind(&numberEqualCheck);
{
Label doubleEqualCheck(env);
Branch(BoolOr(DoubleIsNAN(*doubleLeft), DoubleIsNAN(*doubleRight)), &exit, &doubleEqualCheck);
Bind(&doubleEqualCheck);
{
result = DoubleEqual(*doubleLeft, *doubleRight);
Jump(&exit);
}
}
}
}
Bind(&leftIsNotNumber);
Branch(TaggedIsNumber(right), &exit, &sameVariableCheck);
Bind(&sameVariableCheck);
Branch(Int64Equal(left, right), &strictEqual, &stringEqualCheck);
Bind(&stringEqualCheck);
Branch(BoolAnd(TaggedIsString(left), TaggedIsString(right)), &stringCompare, &bigIntEqualCheck);
Bind(&stringCompare);
{
Label lengthCompare(env);
Label hashcodeCompare(env);
Label contentsCompare(env);
Branch(Int32Equal(ZExtInt1ToInt32(IsUtf16String(left)), ZExtInt1ToInt32(IsUtf16String(right))),
&lengthCompare, &exit);
Bind(&lengthCompare);
Branch(Int32Equal(GetLengthFromString(left), GetLengthFromString(right)), &hashcodeCompare,
&exit);
Bind(&hashcodeCompare);
Branch(Int32Equal(GetHashcodeFromString(glue, left), GetHashcodeFromString(glue, right)), &contentsCompare,
&exit);
Bind(&contentsCompare);
{
result = CallNGCRuntime(glue, RTSTUB_ID(StringsAreEquals), { left, right });
Jump(&exit);
}
}
Bind(&bigIntEqualCheck);
{
Label leftIsBigInt(env);
Label leftIsNotBigInt(env);
Branch(TaggedIsBigInt(left), &leftIsBigInt, &exit);
Bind(&leftIsBigInt);
{
Label rightIsBigInt(env);
Branch(TaggedIsBigInt(right), &rightIsBigInt, &exit);
Bind(&rightIsBigInt);
result = CallNGCRuntime(glue, RTSTUB_ID(BigIntEquals), { left, right });
Jump(&exit);
}
}
Bind(&strictEqual);
{
result = True();
Jump(&exit);
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef Stub::FastEqual(GateRef left, GateRef right)
{
auto env = GetEnvironment();
@ -3690,4 +3824,26 @@ void Stub::ReturnExceptionIfAbruptCompletion(GateRef glue)
env->SubCfgExit();
return;
}
GateRef Stub::GetHashcodeFromString(GateRef glue, GateRef value)
{
auto env = GetEnvironment();
Label subentry(env);
env->SubCfgEntry(&subentry);
Label noRawHashcode(env);
Label exit(env);
DEFVARIABLE(hashcode, VariableType::INT32(), Int32(0));
hashcode = Load(VariableType::INT32(), value, IntPtr(EcmaString::HASHCODE_OFFSET));
Branch(Int32Equal(*hashcode, Int32(0)), &noRawHashcode, &exit);
Bind(&noRawHashcode);
{
hashcode = TaggedCastToInt32(CallRuntime(glue, RTSTUB_ID(ComputeHashcode), { value }));
Store(VariableType::INT32(), glue, value, IntPtr(EcmaString::HASHCODE_OFFSET), *hashcode);
Jump(&exit);
}
Bind(&exit);
auto ret = *hashcode;
env->SubCfgExit();
return ret;
}
} // namespace panda::ecmascript::kungfu

View File

@ -509,6 +509,7 @@ public:
GateRef IsEcmaObject(GateRef obj);
GateRef IsSymbol(GateRef obj);
GateRef IsString(GateRef obj);
GateRef TaggedIsBigInt(GateRef obj);
GateRef IsBigInt(GateRef obj);
GateRef IsJsProxy(GateRef obj);
GateRef IsJSFunctionBase(GateRef obj);
@ -543,6 +544,7 @@ public:
GateRef GetLayoutFromHClass(GateRef hClass);
GateRef GetBitFieldFromHClass(GateRef hClass);
GateRef GetLengthFromString(GateRef value);
GateRef GetHashcodeFromString(GateRef glue, GateRef value);
void SetBitFieldToHClass(GateRef glue, GateRef hClass, GateRef bitfield);
void SetPrototypeToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef proto);
void SetProtoChangeDetailsToHClass(VariableType type, GateRef glue, GateRef hClass,
@ -678,6 +680,7 @@ public:
GateRef GetGlobalOwnProperty(GateRef glue, GateRef receiver, GateRef key);
// fast path
GateRef FastEqual(GateRef left, GateRef right);
GateRef FastStrictEqual(GateRef glue, GateRef left, GateRef right);
GateRef FastMod(GateRef gule, GateRef left, GateRef right);
GateRef FastTypeOf(GateRef left, GateRef right);
GateRef FastMul(GateRef left, GateRef right);

View File

@ -91,4 +91,21 @@ CString EcmaRuntimeStat::GetAllStats() const
}
return statistic.str();
}
EcmaRuntimeStatScope::EcmaRuntimeStatScope(EcmaVM *vm) : vm_(vm)
{
JSRuntimeOptions options = vm_->GetJSOptions();
if (options.IsEnableRuntimeStat()) {
vm_->SetRuntimeStatEnable(true);
}
}
EcmaRuntimeStatScope::~EcmaRuntimeStatScope()
{
JSRuntimeOptions options = vm_->GetJSOptions();
if (options.IsEnableRuntimeStat()) {
vm_->SetRuntimeStatEnable(false);
}
vm_ = nullptr;
}
} // namespace panda::ecmascript

View File

@ -25,7 +25,7 @@ namespace panda::ecmascript {
class EcmaRuntimeStat {
public:
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
explicit EcmaRuntimeStat(const char * const runtimeCallerNames[], int count);
EcmaRuntimeStat(const char * const runtimeCallerNames[], int count);
EcmaRuntimeStat() = default;
virtual ~EcmaRuntimeStat() = default;
@ -43,9 +43,18 @@ private:
CVector<PandaRuntimeCallerStat> callerStat_ {};
};
class EcmaRuntimeStatScope {
public:
explicit EcmaRuntimeStatScope(EcmaVM *vm);
virtual ~EcmaRuntimeStatScope();
private:
EcmaVM *vm_ = nullptr;
};
class RuntimeTimerScope {
public:
explicit RuntimeTimerScope(JSThread *thread, int callerId, EcmaRuntimeStat *stat)
RuntimeTimerScope(JSThread *thread, int callerId, EcmaRuntimeStat *stat)
{
bool statEnabled = thread->GetEcmaVM()->IsRuntimeStatEnabled();
if (!statEnabled || stat == nullptr) {

View File

@ -325,13 +325,8 @@ bool EcmaString::EqualToSplicedString(const EcmaString *str1, const EcmaString *
}
/* static */
bool EcmaString::StringsAreEqual(EcmaString *str1, EcmaString *str2)
bool EcmaString::StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *str2)
{
if ((str1->IsUtf16() != str2->IsUtf16()) || (str1->GetLength() != str2->GetLength()) ||
(str1->GetHashcode() != str2->GetHashcode())) {
return false;
}
if (str1->IsUtf16()) {
Span<const uint16_t> data1(str1->GetDataUtf16(), str1->GetLength());
Span<const uint16_t> data2(str2->GetDataUtf16(), str1->GetLength());
@ -343,6 +338,16 @@ bool EcmaString::StringsAreEqual(EcmaString *str1, EcmaString *str2)
}
}
/* static */
bool EcmaString::StringsAreEqual(EcmaString *str1, EcmaString *str2)
{
if ((str1->IsUtf16() != str2->IsUtf16()) || (str1->GetLength() != str2->GetLength()) ||
(str1->GetHashcode() != str2->GetHashcode())) {
return false;
}
return StringsAreEqualSameUtfEncoding(str1, str2);
}
/* static */
bool EcmaString::StringsAreEqualUtf8(const EcmaString *str1, const uint8_t *utf8Data, uint32_t utf8Len,
bool canBeCompress)

View File

@ -245,6 +245,10 @@ public:
* Compares strings by bytes, It doesn't check canonical unicode equivalence.
*/
static bool StringsAreEqual(EcmaString *str1, EcmaString *str2);
/**
* Two strings have the same type of utf encoding format.
*/
static bool StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *str2);
/**
* Compares strings by bytes, It doesn't check canonical unicode equivalence.
*/

View File

@ -395,6 +395,7 @@ Expected<JSTaggedValue, bool> EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *js
result = InvokeEcmaAotEntrypoint();
} else {
CpuProfilingScope profilingScope(this);
EcmaRuntimeStatScope runtimeStatScope(this);
result = EcmaInterpreter::Execute(&info);
}
if (!thread_->HasPendingException()) {

View File

@ -72,6 +72,7 @@ public:
parser->Add(&icu_data_path_);
parser->Add(&startup_time_);
parser->Add(&snapshotOutputFile_);
parser->Add(&enableRuntimeStat_);
}
bool IsEnableArkTools() const
@ -105,6 +106,21 @@ public:
return enableStubAot_.WasSet();
}
bool IsEnableRuntimeStat() const
{
return enableRuntimeStat_.GetValue();
}
void SetEnableRuntimeStat(bool value)
{
enableRuntimeStat_.SetValue(value);
}
bool WasSetEnableRuntimeStat() const
{
return enableRuntimeStat_.WasSet();
}
std::string GetComStubFile() const
{
return comStubFile_.GetValue();
@ -609,6 +625,8 @@ private:
PandArg<std::string> snapshotOutputFile_ {"snapshot-output-file",
R"(snapshot)",
R"(Path to snapshot output file. Default: "snapshot")"};
PandArg<bool> enableRuntimeStat_ {"enable-runtime-stat", false,
R"(enable statistics of runtime state. Default: false)"};
};
} // namespace panda::ecmascript

View File

@ -618,6 +618,8 @@ namespace panda::ecmascript {
V(Deque, Constructor) \
V(Deque, InsertFront) \
V(Deque, InsertEnd) \
V(Deque, GetFirst) \
V(Deque, GetLast) \
V(Deque, GetFront) \
V(Deque, GetTail) \
V(Deque, Has) \
@ -662,7 +664,9 @@ namespace panda::ecmascript {
V(WaitUpdateFinished) \
V(UpdateRoot) \
V(UpdateWeakReference) \
V(ParallelEvacuationFinalize) \
V(ParallelEvacuator) \
V(ParallelEvacuatorInitialize) \
V(ParallelEvacuatorFinalize) \
V(HugeSpaceExpand) \
V(NonMovableSpaceExpand) \
V(HeapPrepare) \

View File

@ -172,11 +172,11 @@ DEF_RUNTIME_STUBS(CallInternalGetter)
return accessor->CallInternalGet(thread, objHandle).GetRawData();
}
DEF_RUNTIME_STUBS(StringGetHashCode)
DEF_RUNTIME_STUBS(ComputeHashcode)
{
CONVERT_ARG_TAGGED_TYPE_CHECKED(ecmaString, 0);
auto string = reinterpret_cast<EcmaString *>(ecmaString);
uint32_t result = string->GetHashcode();
uint32_t result = string->ComputeHashcode(0);
return JSTaggedValue(static_cast<uint64_t>(result)).GetRawData();
}
@ -1452,7 +1452,7 @@ DEF_RUNTIME_STUBS(DefinefuncDyn)
DEF_RUNTIME_STUBS(DefinefuncDynWithMethodId)
{
RUNTIME_STUBS_HEADER(DefinefuncDynWithMethod);
RUNTIME_STUBS_HEADER(DefinefuncDynWithMethodId);
CONVERT_ARG_TAGGED_CHECKED(methodId, 0);
return RuntimeDefinefuncDynWithMethodId(thread, methodId).GetRawData();
}
@ -1692,6 +1692,16 @@ void RuntimeStubs::MarkingBarrier([[maybe_unused]]uintptr_t argGlue, uintptr_t s
Barriers::Update(slotAddr, objectRegion, value, valueRegion);
}
bool RuntimeStubs::StringsAreEquals(EcmaString *str1, EcmaString *str2)
{
return EcmaString::StringsAreEqualSameUtfEncoding(str1, str2);
}
bool RuntimeStubs::BigIntEquals(JSTaggedType left, JSTaggedType right)
{
return BigInt::Equal(JSTaggedValue(left), JSTaggedValue(right));
}
void RuntimeStubs::Initialize(JSThread *thread)
{
#define DEF_RUNTIME_STUB(name) kungfu::RuntimeStubCSigns::ID_##name

View File

@ -92,12 +92,12 @@ extern "C" void ResumeRspAndReturn(uintptr_t glue, uintptr_t sp);
#define RUNTIME_STUB_WITHOUT_GC_LIST(V) \
V(DebugPrint) \
V(FatalPrint) \
V(InsertOldToNewRSet) \
V(InsertOldToNewRSet) \
V(MarkingBarrier) \
V(DoubleToInt) \
V(FloatMod) \
V(FindElementWithCache) \
V(CallRuntimeWithArgv) \
V(CallRuntimeWithArgv) \
V(JSCall) \
V(JSCallWithArgV) \
V(JSObjectGetMethod) \
@ -122,6 +122,8 @@ extern "C" void ResumeRspAndReturn(uintptr_t glue, uintptr_t sp);
V(PushCallIThisRangeAndDispatchSlowPath) \
V(ResumeRspAndDispatch) \
V(ResumeRspAndReturn) \
V(StringsAreEquals) \
V(BigIntEquals) \
RUNTIME_ASM_STUB_LIST(V)
#define RUNTIME_STUB_WITH_GC_LIST(V) \
@ -134,7 +136,7 @@ extern "C" void ResumeRspAndReturn(uintptr_t glue, uintptr_t sp);
V(ThrowTypeError) \
V(JSProxySetProperty) \
V(GetHash32) \
V(StringGetHashCode) \
V(ComputeHashcode) \
V(GetTaggedArrayPtrTest) \
V(NewInternalString) \
V(NewTaggedArray) \
@ -299,6 +301,8 @@ public:
static JSTaggedType FloatMod(double x, double y);
static int32_t FindElementWithCache(uintptr_t argGlue, JSTaggedType hClass,
JSTaggedType key, int32_t num);
static bool StringsAreEquals(EcmaString *str1, EcmaString *str2);
static bool BigIntEquals(JSTaggedType left, JSTaggedType right);
private:
static void PrintHeapReginInfo(uintptr_t argGlue);