mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-30 13:40:51 +00:00
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:
parent
81b05f5538
commit
06c6451611
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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++) {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
2
ecmascript/ts_types/lib_ark_builtins.d.ts
vendored
2
ecmascript/ts_types/lib_ark_builtins.d.ts
vendored
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user