Optimize LocaleCompare for AOT

1. Add caches for locales
2. Add fastpath for locale string compare
3. Add pgo for bound function
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7F6ZW?from=project-issue
Signed-off-by: zhangyukun <zhangyukun8@huawei.com>

Change-Id: I869ec1a41eaaf7098627277a5ec9b3ce7a245dc4
This commit is contained in:
zhangyukun 2023-06-21 13:59:29 +08:00
parent 81b05f5538
commit 06c6451611
18 changed files with 286 additions and 26 deletions

View File

@ -64,7 +64,8 @@ namespace panda::ecmascript::kungfu {
V(ACOS) \
V(ATAN) \
V(ABS) \
V(FLOOR)
V(FLOOR) \
V(LocaleCompare)
class BuiltinsStubCSigns {
public:
@ -161,6 +162,7 @@ public:
{"atan", ATAN},
{"abs", ABS},
{"floor", FLOOR},
{"localeCompare", LocaleCompare},
};
if (str2BuiltinId.count(idStr) > 0) {
return str2BuiltinId.at(idStr);

View File

@ -33,6 +33,9 @@ void BuiltinLowering::LowerTypedCallBuitin(GateRef gate)
case BUILTINS_STUB_ID(ATAN):
LowerTypedTrigonometric(gate, id);
break;
case BUILTINS_STUB_ID(LocaleCompare):
LowerTypedLocaleCompare(gate);
break;
default:
break;
}
@ -176,6 +179,64 @@ GateRef BuiltinLowering::TypedAbs(GateRef gate)
return ret;
}
GateRef BuiltinLowering::LowerCallRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args,
bool useLabel)
{
const std::string name = RuntimeStubCSigns::GetRTName(index);
if (useLabel) {
GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, gate, name.c_str());
return result;
} else {
const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
GateRef target = builder_.IntPtr(index);
GateRef result = builder_.Call(cs, glue, target, builder_.GetDepend(), args, gate, name.c_str());
return result;
}
}
void BuiltinLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value, bool noThrow)
{
if (!noThrow) {
GateRef state = builder_.GetState();
// copy depend-wire of hirGate to value
GateRef depend = builder_.GetDepend();
// exception value
GateRef exceptionVal = builder_.ExceptionConstant();
// compare with trampolines result
GateRef equal = builder_.Equal(value, exceptionVal);
auto ifBranch = builder_.Branch(state, equal);
GateRef ifTrue = builder_.IfTrue(ifBranch);
GateRef ifFalse = builder_.IfFalse(ifBranch);
GateRef eDepend = builder_.DependRelay(ifTrue, depend);
GateRef sDepend = builder_.DependRelay(ifFalse, depend);
StateDepend success(ifFalse, sDepend);
StateDepend exception(ifTrue, eDepend);
acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
} else {
acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value);
}
}
void BuiltinLowering::LowerTypedLocaleCompare(GateRef gate)
{
GateRef glue = acc_.GetGlueFromArgList();
uint32_t index = 0;
GateRef thisObj = acc_.GetValueIn(gate, index++);
GateRef a0 = acc_.GetValueIn(gate, index++);
GateRef a1 = acc_.GetValueIn(gate, index++);
GateRef a2 = acc_.GetValueIn(gate, index++);
std::vector<GateRef> args;
args.reserve(index);
args.emplace_back(thisObj);
args.emplace_back(a0);
args.emplace_back(a1);
args.emplace_back(a2);
GateRef result = LowerCallRuntime(glue, gate, RTSTUB_ID(LocaleCompare), args);
ReplaceHirWithValue(gate, result);
}
GateRef BuiltinLowering::LowerCallTargetCheck(Environment *env, GateRef gate)
{
builder_.SetEnvironment(env);

View File

@ -30,12 +30,17 @@ public:
GateRef LowerCallTargetCheck(Environment *env, GateRef gate);
void LowerTypedSqrt(GateRef gate);
GateRef CheckPara(GateRef gate, GateRef funcCheck);
void LowerTypedLocaleCompare(GateRef gate);
private:
void LowerTypedTrigonometric(GateRef gate, BuiltinsStubCSigns::ID id);
GateRef TypedTrigonometric(GateRef gate, BuiltinsStubCSigns::ID id);
GateRef IntToTaggedIntPtr(GateRef x);
void LowerTypedAbs(GateRef gate);
GateRef TypedAbs(GateRef gate);
GateRef LowerCallRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args,
bool useLabel = false);
void ReplaceHirWithValue(GateRef hirGate, GateRef value, bool noThrow = false);
Circuit *circuit_ {nullptr};
CircuitBuilder builder_;

View File

@ -1085,6 +1085,20 @@ inline GateRef CircuitBuilder::TypedCallBuiltin(GateRef hirGate, GateRef x, Buil
return numberMathOp;
}
inline GateRef CircuitBuilder::TypedCallThis3Builtin(GateRef hirGate, GateRef thisObj, GateRef a0, GateRef a1,
GateRef a2, BuiltinsStubCSigns::ID id)
{
auto currentLabel = env_->GetCurrentLabel();
auto currentControl = currentLabel->GetControl();
auto currentDepend = currentLabel->GetDepend();
GateRef idGate = Int8(static_cast<int8_t>(id));
auto numberMathOp = TypedCallOperator(hirGate, MachineType::I64,
{currentControl, currentDepend, thisObj, a0, a1, a2, idGate});
currentLabel->SetControl(numberMathOp);
currentLabel->SetDepend(numberMathOp);
return numberMathOp;
}
inline GateRef CircuitBuilder::GetMethodId(GateRef func)
{
GateRef method = GetMethodFromFunction(func);

View File

@ -261,6 +261,8 @@ public:
GateRef DeoptCheck(GateRef condition, GateRef frameState, DeoptType type);
GateRef TypedCallOperator(GateRef hirGate, MachineType type, const std::initializer_list<GateRef>& args);
inline GateRef TypedCallBuiltin(GateRef hirGate, GateRef x, BuiltinsStubCSigns::ID id);
inline GateRef TypedCallThis3Builtin(GateRef hirGate, GateRef thisObj, GateRef a0, GateRef a1, GateRef a2,
BuiltinsStubCSigns::ID id);
GateRef TypeConvert(MachineType type, GateType typeFrom, GateType typeTo, const std::vector<GateRef>& inList);
GateRef AddWithOverflow(GateRef left, GateRef right);
GateRef SubWithOverflow(GateRef left, GateRef right);

View File

@ -880,15 +880,26 @@ void TSHCRLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, GateRef a0,
acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
}
BuiltinsStubCSigns::ID TSHCRLowering::GetBuiltinId(GateRef func)
void TSHCRLowering::SpeculateCallThis3Builtin(GateRef gate, BuiltinsStubCSigns::ID id)
{
GateRef thisObj = acc_.GetValueIn(gate, 0);
GateRef a0 = acc_.GetValueIn(gate, 1); // 1: the first-para
GateRef a1 = acc_.GetValueIn(gate, 2); // 2: the third-para
GateRef a2 = acc_.GetValueIn(gate, 3); // 3: the fourth-para
GateRef result = builder_.TypedCallThis3Builtin(gate, thisObj, a0, a1, a2, id);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
}
BuiltinsStubCSigns::ID TSHCRLowering::GetBuiltinId(BuiltinTypeId id, GateRef func)
{
GateType funcType = acc_.GetGateType(func);
if (!tsManager_->IsBuiltinMath(funcType)) {
if (!tsManager_->IsBuiltinObject(id, funcType)) {
return BuiltinsStubCSigns::ID::NONE;
}
std::string name = tsManager_->GetFuncName(funcType);
BuiltinsStubCSigns::ID id = BuiltinsStubCSigns::GetBuiltinId(name);
return id;
BuiltinsStubCSigns::ID stubId = BuiltinsStubCSigns::GetBuiltinId(name);
return stubId;
}
void TSHCRLowering::CheckCallTargetAndLowerCall(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
@ -971,7 +982,7 @@ void TSHCRLowering::LowerTypedCallArg1(GateRef gate)
}
GateRef a0Value = acc_.GetValueIn(gate, 0);
GateType a0Type = acc_.GetGateType(a0Value);
BuiltinsStubCSigns::ID id = GetBuiltinId(func);
BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::MATH, func);
if (id != BuiltinsStubCSigns::ID::NONE && a0Type.IsNumberType()) {
AddProfiling(gate);
SpeculateCallBuiltin(gate, func, a0Value, id);
@ -1106,7 +1117,7 @@ void TSHCRLowering::LowerTypedCallthis1(GateRef gate)
GateRef a0 = acc_.GetValueIn(gate, 1); // 1:parameter index
GateType a0Type = acc_.GetGateType(a0);
GateRef func = acc_.GetValueIn(gate, 2); // 2:function
BuiltinsStubCSigns::ID id = GetBuiltinId(func);
BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::MATH, func);
if (id != BuiltinsStubCSigns::ID::NONE && a0Type.IsNumberType()) {
AddProfiling(gate);
SpeculateCallBuiltin(gate, func, a0, id);
@ -1138,6 +1149,13 @@ void TSHCRLowering::LowerTypedCallthis3(GateRef gate)
// 5: number of value inputs
ASSERT(acc_.GetNumValueIn(gate) == 5);
GateRef func = acc_.GetValueIn(gate, 4); // 4: func
BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::STRING, func);
if (id == BuiltinsStubCSigns::ID::LocaleCompare) {
AddProfiling(gate);
SpeculateCallThis3Builtin(gate, id);
return;
}
if (!CanOptimizeAsFastCall(func)) {
return;
}

View File

@ -133,7 +133,8 @@ private:
void SpeculateNumber(GateRef gate);
void SpeculateConditionJump(GateRef gate, bool flag);
void SpeculateCallBuiltin(GateRef gate, GateRef func, GateRef a0, BuiltinsStubCSigns::ID Op);
BuiltinsStubCSigns::ID GetBuiltinId(GateRef func);
void SpeculateCallThis3Builtin(GateRef gate, BuiltinsStubCSigns::ID id);
BuiltinsStubCSigns::ID GetBuiltinId(BuiltinTypeId id, GateRef func);
void DeleteConstDataIfNoUser(GateRef gate);
void AddProfiling(GateRef gate);

View File

@ -74,6 +74,7 @@ inline uintptr_t GlobalEnvConstants::GetGlobalConstantAddr(ConstantIndex index)
GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET_IMPL) // NOLINT(readability-const-return-type)
GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET_IMPL) // NOLINT(readability-const-return-type)
GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET_IMPL) // NOLINT(readability-const-return-type)
GLOBAL_ENV_CACHES(DECL_GET_IMPL) // NOLINT(readability-const-return-type)
#undef DECL_GET_IMPL
// clang-format on
} // namespace panda::ecmascript

View File

@ -79,6 +79,7 @@ void GlobalEnvConstants::Init(JSThread *thread, JSHClass *hClass)
{
InitRootsClass(thread, hClass);
InitGlobalConstant(thread);
InitGlobalCaches();
}
void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass)
@ -609,6 +610,19 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread)
InitClassConstructorOptimizedClass(factory);
}
void GlobalEnvConstants::InitGlobalCaches()
{
SetConstant(ConstantIndex::CACHED_JSCOLLATOR_LOCALES_INDEX, JSTaggedValue::Undefined());
}
void GlobalEnvConstants::SetCachedLocales(JSTaggedValue value)
{
JSTaggedValue cached = GetCachedJSCollatorLocales();
if (cached.IsUndefined()) {
SetConstant(ConstantIndex::CACHED_JSCOLLATOR_LOCALES_INDEX, value);
}
}
void GlobalEnvConstants::InitJSAPIContainers()
{
for (size_t i = GetJSAPIContainersBegin(); i <= GetJSAPIContainersEnd(); i++) {

View File

@ -451,7 +451,9 @@ class ObjectFactory;
V(JSTaggedValue, FunctionPrototypeAccessor, FUNCTION_PROTOTYPE_ACCESSOR, ecma_roots_accessor) \
V(JSTaggedValue, FunctionNameAccessor, FUNCTION_NAME_ACCESSOR, ecma_roots_accessor) \
V(JSTaggedValue, ArrayLengthAccessor, ARRAY_LENGTH_ACCESSOR, ecma_roots_accessor)
/* RealmConstant */
#define GLOBAL_ENV_CACHES(V) \
V(JSTaggedValue, CachedJSCollatorLocales, CACHED_JSCOLLATOR_LOCALES_INDEX, cachedCollatorLocales)
// ConstantIndex used for explicit visit each constant.
enum class ConstantIndex : size_t {
@ -459,6 +461,7 @@ enum class ConstantIndex : size_t {
#define INDEX_FILTER(Type, Name, Index, Desc) Index,
GLOBAL_ENV_CONSTANT_CLASS(INDEX_FILTER) GLOBAL_ENV_CONSTANT_SPECIAL(INDEX_FILTER)
GLOBAL_ENV_CONSTANT_CONSTANT(INDEX_FILTER) GLOBAL_ENV_CONSTANT_ACCESSOR(INDEX_FILTER)
GLOBAL_ENV_CACHES(INDEX_FILTER)
#undef INDEX_FILTER
CONSTATNT_COUNT,
@ -492,11 +495,14 @@ public:
void InitGlobalConstantSpecial(JSThread *thread);
void InitGlobalConstant(JSThread *thread);
void InitGlobalCaches();
void InitJSAPIContainers();
void InitSpecialForSnapshot();
void InitClassConstructorOptimizedClass(ObjectFactory *factory);
void SetCachedLocales(JSTaggedValue value);
void SetConstant(ConstantIndex index, JSTaggedValue value);
template<typename T>
@ -514,6 +520,7 @@ public:
GLOBAL_ENV_CONSTANT_SPECIAL(DECL_GET)
GLOBAL_ENV_CONSTANT_CONSTANT(DECL_GET)
GLOBAL_ENV_CONSTANT_ACCESSOR(DECL_GET)
GLOBAL_ENV_CACHES(DECL_GET)
#undef DECL_GET
void VisitRangeSlot(const RootRangeVisitor &visitor)

View File

@ -37,12 +37,23 @@ const std::map<CaseFirstOption, UColAttributeValue> JSCollator::uColAttributeVal
{CaseFirstOption::UNDEFINED, UCOL_OFF}
};
JSHandle<TaggedArray> JSCollator::GetAvailableLocales(JSThread *thread)
JSHandle<TaggedArray> JSCollator::GetAvailableLocales(JSThread *thread, bool enableLocaleCache)
{
const char *key = nullptr;
const char *path = JSCollator::uIcuDataColl.c_str();
// key and path are const, so we can cache the result
if (enableLocaleCache) {
JSHandle<JSTaggedValue> cachedLocales = thread->GlobalConstants()->GetHandledCachedJSCollatorLocales();
if (cachedLocales->IsHeapObject()) {
return JSHandle<TaggedArray>(cachedLocales);
}
}
std::vector<std::string> availableStringLocales = intl::LocaleHelper::GetAvailableLocales(thread, key, path);
JSHandle<TaggedArray> availableLocales = JSLocale::ConstructLocaleList(thread, availableStringLocales);
if (enableLocaleCache) {
GlobalEnvConstants *constants = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
constants->SetCachedLocales(availableLocales.GetTaggedValue());
}
return availableLocales;
}
@ -68,7 +79,8 @@ JSHandle<JSCollator> JSCollator::InitializeCollator(JSThread *thread,
const JSHandle<JSCollator> &collator,
const JSHandle<JSTaggedValue> &locales,
const JSHandle<JSTaggedValue> &options,
bool forIcuCache)
bool forIcuCache,
bool enableLocaleCache)
{
EcmaVM *ecmaVm = thread->GetEcmaVM();
ObjectFactory *factory = ecmaVm->GetFactory();
@ -143,7 +155,7 @@ JSHandle<JSCollator> JSCollator::InitializeCollator(JSThread *thread,
if (requestedLocales->GetLength() == 0) {
availableLocales = factory->EmptyArray();
} else {
availableLocales = GetAvailableLocales(thread);
availableLocales = GetAvailableLocales(thread, enableLocaleCache);
}
ResolvedLocale r =
JSLocale::ResolveLocale(thread, availableLocales, requestedLocales, matcher, relevantExtensionKeys);
@ -460,4 +472,39 @@ JSTaggedValue JSCollator::CompareStrings(const icu::Collator *icuCollator, const
return JSTaggedValue(result);
}
JSTaggedValue JSCollator::FastCompareStrings(JSThread *thread, const icu::Collator *icuCollator,
const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2)
{
if (*string1 == *string2) {
return JSTaggedValue(UCollationResult::UCOL_EQUAL);
}
auto flatString1 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string1));
auto flatString2 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), string2));
UCollationResult result;
UErrorCode status = U_ZERO_ERROR;
{
DISALLOW_GARBAGE_COLLECTION;
CString str1 = ConvertToString(*flatString1, StringConvertedUsage::LOGICOPERATION);
icu::StringPiece stringPiece1(str1.c_str());
if (!stringPiece1.empty()) {
CString str2 = ConvertToString(*flatString2, StringConvertedUsage::LOGICOPERATION);
icu::StringPiece stringPiece2(str2.c_str());
if (!stringPiece2.empty()) {
result = icuCollator->compareUTF8(stringPiece1, stringPiece2, status);
return JSTaggedValue(result);
}
}
icu::UnicodeString uString1 = EcmaStringToUString(flatString1);
icu::UnicodeString uString2 = EcmaStringToUString(flatString2);
result = icuCollator->compare(uString1, uString2, status);
ASSERT(U_SUCCESS(status));
}
return JSTaggedValue(result);
}
} // namespace panda::ecmascript

View File

@ -84,18 +84,23 @@ public:
static JSHandle<JSCollator> InitializeCollator(JSThread *thread, const JSHandle<JSCollator> &collator,
const JSHandle<JSTaggedValue> &locales,
const JSHandle<JSTaggedValue> &options,
bool forIcuCache = false);
bool forIcuCache = false,
bool enableLocaleCache = false);
static icu::Collator *GetCachedIcuCollator(JSThread *thread, const JSHandle<JSTaggedValue> &locales);
// 11.3.4 Intl.Collator.prototype.resolvedOptions ()
static JSHandle<JSObject> ResolvedOptions(JSThread *thread, const JSHandle<JSCollator> &collator);
static JSHandle<TaggedArray> GetAvailableLocales(JSThread *thread);
static JSHandle<TaggedArray> GetAvailableLocales(JSThread *thread, bool enableLocaleCache = false);
static JSTaggedValue CompareStrings(const icu::Collator *icuCollator, const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2);
static JSTaggedValue FastCompareStrings(JSThread *thread, const icu::Collator *icuCollator,
const JSHandle<EcmaString> &string1,
const JSHandle<EcmaString> &string2);
private:
static CaseFirstOption StringToCaseFirstOption(const std::string &str);

View File

@ -276,7 +276,7 @@ inline JSHandle<JSTaggedValue> JSTaggedValue::RequireObjectCoercible(JSThread *t
const JSHandle<JSTaggedValue> &tagged,
const char *message)
{
if (tagged->IsUndefined() || tagged->IsNull()) {
if (tagged->IsUndefinedOrNull()) {
THROW_TYPE_ERROR_AND_RETURN(thread, message, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
}
return tagged;

View File

@ -54,6 +54,14 @@
#include "ecmascript/tagged_node.h"
#include "ecmascript/ts_types/ts_manager.h"
#include "libpandafile/bytecode_instruction-inl.h"
#ifdef ARK_SUPPORT_INTL
#include "ecmascript/js_collator.h"
#include "ecmascript/js_locale.h"
#else
#ifndef ARK_NOT_SUPPORT_INTL_GLOBAL
#include "ecmascript/intl/global_intl_helper.h"
#endif
#endif
namespace panda::ecmascript {
#if defined(__clang__)
@ -2285,7 +2293,14 @@ JSTaggedValue RuntimeStubs::CallBoundFunction(EcmaRuntimeCallInfo *info)
THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot called without 'new'",
JSTaggedValue::Exception());
}
if (thread->IsPGOProfilerEnable()) {
ECMAObject *callTarget = reinterpret_cast<ECMAObject*>(targetFunc.GetTaggedValue().GetTaggedObject());
ASSERT(callTarget != nullptr);
Method *method = callTarget->GetCallTarget();
if (!method->IsNativeWithCallField()) {
thread->GetEcmaVM()->GetPGOProfiler()->ProfileCall(targetFunc.GetTaggedType());
}
}
JSHandle<TaggedArray> boundArgs(thread, boundFunc->GetBoundArguments());
const int32_t boundLength = static_cast<int32_t>(boundArgs->GetLength());
const int32_t argsLength = static_cast<int32_t>(info->GetArgsNumber()) + boundLength;
@ -2338,6 +2353,65 @@ DEF_RUNTIME_STUBS(AotInlineTrace)
return JSTaggedValue::Undefined().GetRawData();
}
DEF_RUNTIME_STUBS(LocaleCompare)
{
RUNTIME_STUBS_HEADER(LocaleCompare);
JSHandle<JSTaggedValue> thisTag = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
JSHandle<JSTaggedValue> thatTag = GetHArg<JSTaggedValue>(argv, argc, 1); // 1: means the first parameter
JSHandle<JSTaggedValue> locales = GetHArg<JSTaggedValue>(argv, argc, 2); // 2: means the second parameter
JSHandle<JSTaggedValue> options = GetHArg<JSTaggedValue>(argv, argc, 3); // 3: means the third parameter
JSHandle<JSTaggedValue> thisObj(JSTaggedValue::RequireObjectCoercible(thread, thisTag));
[[maybe_unused]] JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisObj);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
[[maybe_unused]] JSHandle<EcmaString> thatHandle = JSTaggedValue::ToString(thread, thatTag);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
[[maybe_unused]] bool cacheable = options->IsUndefined() && (locales->IsUndefined() || locales->IsString());
#ifdef ARK_SUPPORT_INTL
if (cacheable) {
auto collator = JSCollator::GetCachedIcuCollator(thread, locales);
if (collator != nullptr) {
JSTaggedValue result = JSCollator::CompareStrings(collator, thisHandle, thatHandle);
return result.GetRawData();
}
}
EcmaVM *ecmaVm = thread->GetEcmaVM();
ObjectFactory *factory = ecmaVm->GetFactory();
JSHandle<JSTaggedValue> ctor = ecmaVm->GetGlobalEnv()->GetCollatorFunction();
JSHandle<JSCollator> collator =
JSHandle<JSCollator>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor)));
JSHandle<JSCollator> initCollator =
JSCollator::InitializeCollator(thread, collator, locales, options, cacheable, true);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception().GetRawData());
icu::Collator *icuCollator = nullptr;
if (cacheable) {
icuCollator = JSCollator::GetCachedIcuCollator(thread, locales);
ASSERT(icuCollator != nullptr);
} else {
icuCollator = initCollator->GetIcuCollator();
}
JSTaggedValue result = JSCollator::FastCompareStrings(thread, icuCollator, thisHandle, thatHandle);
return result.GetRawData();
#else
#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL
ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare");
#else
intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::Collator);
auto collator = gh.GetGlobalObject<intl::GlobalCollator>(thread,
locales, options, intl::GlobalFormatterType::Collator, cacheable);
if (collator == nullptr) {
LOG_ECMA(ERROR) << "BuiltinsString::LocaleCompare:collator is nullptr";
}
ASSERT(collator != nullptr);
auto result = collator->Compare(EcmaStringAccessor(thisHandle).ToStdString(),
EcmaStringAccessor(thatHandle).ToStdString());
return JSTaggedValue(result).GetRawData();
#endif
#endif
}
void RuntimeStubs::StartCallTimer(uintptr_t argGlue, JSTaggedType func, bool isAot)
{
auto thread = JSThread::GlueToJSThread(argGlue);

View File

@ -304,7 +304,8 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(SlowFlattenString) \
V(NotifyConcurrentResult) \
V(OtherToNumber) \
V(AotInlineTrace)
V(AotInlineTrace) \
V(LocaleCompare)
#define RUNTIME_STUB_LIST(V) \
RUNTIME_ASM_STUB_LIST(V) \

View File

@ -613,7 +613,7 @@ declare class String extends Object {
lastIndexOf(searchString: string, position?: number): number;
localeCompare(that: string): number;
localeCompare(that: string, locale?: string, options?: any): number;
match(regexp: string | RegExp): RegExpMatchArray | null;

View File

@ -1330,7 +1330,7 @@ JSHandle<TaggedArray> TSManager::GenerateExportTableFromLiteral(const JSPandaFil
return typeOfExportedSymbols;
}
bool TSManager::IsBuiltinMath(kungfu::GateType funcType) const
bool TSManager::IsBuiltinObject(BuiltinTypeId id, kungfu::GateType funcType) const
{
DISALLOW_GARBAGE_COLLECTION;
GlobalTSTypeRef funcGT = funcType.GetGTRef();
@ -1339,17 +1339,17 @@ bool TSManager::IsBuiltinMath(kungfu::GateType funcType) const
}
if (IsBuiltinsDTSEnabled()) {
uint32_t idx = static_cast<uint32_t>(BuiltinTypeId::MATH);
uint32_t idx = static_cast<uint32_t>(id);
const JSPandaFile *builtinPandaFile = GetBuiltinPandaFile();
uint32_t mathOffset = GetBuiltinOffset(idx);
bool hasCreatedGT = HasCreatedGT(builtinPandaFile, mathOffset);
uint32_t builtinOffset = GetBuiltinOffset(idx);
bool hasCreatedGT = HasCreatedGT(builtinPandaFile, builtinOffset);
if (hasCreatedGT) {
JSHandle<JSTaggedValue> funcTsType = GetTSType(funcGT);
ASSERT(funcTsType->IsTSFunctionType());
JSHandle<TSFunctionType> functionType = JSHandle<TSFunctionType>(funcTsType);
auto name = functionType->GetName();
auto gt = GetGTFromOffset(builtinPandaFile, mathOffset);
auto gt = GetGTFromOffset(builtinPandaFile, builtinOffset);
auto tsType = GetTSType(gt);
ASSERT(tsType->IsTSClassType());
JSHandle<TSClassType> classType(tsType);
@ -1358,8 +1358,16 @@ bool TSManager::IsBuiltinMath(kungfu::GateType funcType) const
TSObjLayoutInfo *itLayout = TSObjLayoutInfo::Cast(layout.GetTaggedObject());
int index = itLayout->GetElementIndexByKey(name);
if (index != -1) {
auto mathFuncGt = GlobalTSTypeRef(itLayout->GetTypeId(index).GetInt());
return mathFuncGt == funcGT;
auto builtinFuncGt = GlobalTSTypeRef(itLayout->GetTypeId(index).GetInt());
return builtinFuncGt == funcGT;
}
JSHandle<TSObjectType> prototypeType(thread_, classType->GetPrototypeType());
JSTaggedValue prototypeLayout = prototypeType->GetObjLayoutInfo();
TSObjLayoutInfo *pPrototypeLayout = TSObjLayoutInfo::Cast(prototypeLayout.GetTaggedObject());
index = pPrototypeLayout->GetElementIndexByKey(name);
if (index != -1) {
auto builtinFuncGt = GlobalTSTypeRef(pPrototypeLayout->GetTypeId(index).GetInt());
return builtinFuncGt == funcGT;
}
}
}

View File

@ -553,7 +553,7 @@ public:
bool PUBLIC_API IsBuiltin(kungfu::GateType funcType) const;
bool PUBLIC_API IsBuiltinMath(kungfu::GateType funcType) const;
bool PUBLIC_API IsBuiltinObject(BuiltinTypeId id, kungfu::GateType funcType) const;
inline const JSPandaFile *GetBuiltinPandaFile() const
{