!5399 speed reduce and sort

Merge pull request !5399 from wangyue/arraysort
This commit is contained in:
openharmony_ci 2023-12-02 01:42:43 +00:00 committed by Gitee
commit ec2596517e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
18 changed files with 595 additions and 48 deletions

View File

@ -1624,6 +1624,37 @@ JSTaggedValue BuiltinsArray::Push(EcmaRuntimeCallInfo *argv)
return GetTaggedDouble(len);
}
JSTaggedValue BuiltinsArray::ReduceUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisHandle,
JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, JSMutableHandle<JSTaggedValue> &accumulator,
JSHandle<JSTaggedValue> &callbackFnHandle)
{
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
JSTaggedValue callResult = JSTaggedValue::Undefined();
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
while (k < len) {
bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (exists) {
JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
key.Update(JSTaggedValue(k));
JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined();
const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(), key.GetTaggedValue(),
thisObjVal.GetTaggedValue());
callResult = JSFunction::Call(info);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
accumulator.Update(callResult);
}
k++;
}
return accumulator.GetTaggedValue();
}
// 22.1.3.18 Array.prototype.reduce ( callbackfn [ , initialValue ] )
JSTaggedValue BuiltinsArray::Reduce(EcmaRuntimeCallInfo *argv)
{
@ -1631,7 +1662,6 @@ JSTaggedValue BuiltinsArray::Reduce(EcmaRuntimeCallInfo *argv)
BUILTINS_API_TRACE(argv->GetThread(), Array, Reduce);
JSThread *thread = argv->GetThread();
[[maybe_unused]] EcmaHandleScope handleScope(thread);
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
uint32_t argc = argv->GetArgsNumber();
// 1. Let O be ToObject(this value).
@ -1694,43 +1724,7 @@ JSTaggedValue BuiltinsArray::Reduce(EcmaRuntimeCallInfo *argv)
if (thisObjVal->IsStableJSArray(thread)) {
JSStableArray::Reduce(thread, thisObjHandle, callbackFnHandle, accumulator, k, len);
}
// 10. Repeat, while k < len
// a. Let Pk be ToString(k).
// b. Let kPresent be HasProperty(O, Pk).
// c. ReturnIfAbrupt(kPresent).
// d. If kPresent is true, then
// i. Let kValue be Get(O, Pk).
// ii. ReturnIfAbrupt(kValue).
// iii. Let accumulator be Call(callbackfn, undefined, «accumulator, kValue, k, O»).
// iv. ReturnIfAbrupt(accumulator).
// e. Increase k by 1.
JSTaggedValue callResult = JSTaggedValue::Undefined();
JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
while (k < len) {
bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (exists) {
JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
key.Update(JSTaggedValue(k));
JSHandle<JSTaggedValue> thisArgHandle = globalConst->GetHandledUndefined();
const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O»
JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(), key.GetTaggedValue(),
thisObjVal.GetTaggedValue());
callResult = JSFunction::Call(info);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
accumulator.Update(callResult);
}
k++;
}
// 11. Return accumulator.
return accumulator.GetTaggedValue();
return ReduceUnStableJSArray(thread, thisHandle, thisObjVal, k, len, accumulator, callbackFnHandle);
}
// 22.1.3.19 Array.prototype.reduceRight ( callbackfn [ , initialValue ] )

View File

@ -79,7 +79,7 @@
/* Array.prototype.push ( ...items ) */ \
V("push", Push, 1, ArrayPush) \
/* Array.prototype.reduce ( callbackfn [ , initialValue ] ) */ \
V("reduce", Reduce, 1, INVALID) \
V("reduce", Reduce, 1, ArrayReduce) \
/* Array.prototype.reduceRight ( callbackfn [ , initialValue ] ) */ \
V("reduceRight", ReduceRight, 1, INVALID) \
/* Array.prototype.reverse ( ) */ \
@ -230,6 +230,9 @@ public:
// (4) Array.prototype[@@unscopables]()
return GetArrayPrototypeFunctions().Size() + 4;
}
static JSTaggedValue ReduceUnStableJSArray(JSThread *thread, JSHandle<JSTaggedValue> &thisHandle,
JSHandle<JSTaggedValue> &thisObjVal, int64_t k, int64_t len, JSMutableHandle<JSTaggedValue> &accumulator,
JSHandle<JSTaggedValue> &callbackFnHandle);
private:
#define BUILTIN_ARRAY_FUNCTION_ENTRY(name, method, length, id) \

View File

@ -23,6 +23,7 @@
#include "ecmascript/runtime_call_id.h"
#include "ecmascript/js_iterator.h"
#include "ecmascript/compiler/access_object_stub_builder.h"
#include "ecmascript/base/array_helper.h"
namespace panda::ecmascript::kungfu {
void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef numArgs,
@ -598,6 +599,262 @@ void BuiltinsArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef nu
}
}
void BuiltinsArrayStubBuilder::Sort(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
Label isHeapObject(env);
Label isJsArray(env);
Label isStability(env);
Label defaultConstr(env);
Label notCOWArray(env);
Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
Bind(&isHeapObject);
Branch(IsJsArray(thisValue), &isJsArray, slowPath);
Bind(&isJsArray);
Branch(HasConstructor(thisValue), slowPath, &defaultConstr);
Bind(&defaultConstr);
Branch(IsStableJSArray(glue, thisValue), &isStability, slowPath);
Bind(&isStability);
Branch(IsJsCOWArray(thisValue), slowPath, &notCOWArray);
Bind(&notCOWArray);
Label argUndefined(env);
GateRef callbackFnHandle = GetCallArg0(numArgs);
GateRef isUndefined = TaggedIsUndefined(callbackFnHandle);
Branch(isUndefined, &argUndefined, slowPath);
Bind(&argUndefined);
{
Label isStableJSArray(env);
GateRef stableArray = IsStableJSArray(glue, thisValue);
Branch(BoolAnd(stableArray, isUndefined), &isStableJSArray, slowPath);
Bind(&isStableJSArray);
{
GateRef thisEles = GetElementsArray(thisValue);
GateRef len = ZExtInt32ToInt64(GetArrayLength(thisValue));
DEFVARIABLE(i, VariableType::INT64(), Int64(1));
DEFVARIABLE(presentValue, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(middleValue, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(previousValue, VariableType::JS_ANY(), Undefined());
Label loopHead(env);
Label loopEnd(env);
Label next(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
Branch(Int64LessThan(*i, len), &next, &loopExit);
Bind(&next);
DEFVARIABLE(beginIndex, VariableType::INT64(), Int64(0));
DEFVARIABLE(endIndex, VariableType::INT64(), *i);
presentValue = GetValueFromTaggedArray(thisEles, *i);
Label loopHead1(env);
Label loopEnd1(env);
Label next1(env);
Label loopExit1(env);
Jump(&loopHead1);
LoopBegin(&loopHead1);
{
Branch(Int64LessThan(*beginIndex, *endIndex), &next1, &loopExit1);
Bind(&next1);
GateRef sum = Int64Add(*beginIndex, *endIndex);
GateRef middleIndex = Int64Div(sum, Int64(2)); // 2 : half
middleValue = GetValueFromTaggedArray(thisEles, middleIndex);
Label isInt(env);
Branch(BoolAnd(TaggedIsInt(*middleValue), TaggedIsInt(*presentValue)), &isInt, slowPath);
Bind(&isInt);
GateRef compareResult =
CallNGCRuntime(glue, RTSTUB_ID(FastArraySort), {*middleValue, *presentValue});
Label less0(env);
Label greater0(env);
Branch(Int32LessThanOrEqual(compareResult, Int32(0)), &less0, &greater0);
Bind(&greater0);
{
endIndex = middleIndex;
Jump(&loopEnd1);
}
Bind(&less0);
{
beginIndex = middleIndex;
beginIndex = Int64Add(*beginIndex, Int64(1));
Jump(&loopEnd1);
}
}
Bind(&loopEnd1);
LoopEnd(&loopHead1);
Bind(&loopExit1);
Label shouldCopy(env);
GateRef isGreater0 = Int64GreaterThanOrEqual(*endIndex, Int64(0));
GateRef lessI = Int64LessThan(*endIndex, *i);
Branch(BoolAnd(isGreater0, lessI), &shouldCopy, &loopEnd);
Bind(&shouldCopy);
DEFVARIABLE(j, VariableType::INT64(), *i);
Label loopHead2(env);
Label loopEnd2(env);
Label next2(env);
Label loopExit2(env);
Jump(&loopHead2);
LoopBegin(&loopHead2);
{
Branch(Int64GreaterThan(*j, *endIndex), &next2, &loopExit2);
Bind(&next2);
previousValue = GetValueFromTaggedArray(thisEles, Int64Sub(*j, Int64(1)));
SetValueToTaggedArray(VariableType::JS_ANY(), glue, thisEles, *j, *previousValue);
Jump(&loopEnd2);
}
Bind(&loopEnd2);
j = Int64Sub(*j, Int64(1));
LoopEnd(&loopHead2);
Bind(&loopExit2);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, thisEles, *endIndex, *presentValue);
Jump(&loopEnd);
}
Bind(&loopEnd);
i = Int64Add(*i, Int64(1));
LoopEnd(&loopHead);
Bind(&loopExit);
result->WriteVariable(thisValue);
Jump(exit);
}
}
}
void BuiltinsArrayStubBuilder::Reduce(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
{
auto env = GetEnvironment();
DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0));
Label isHeapObject(env);
Label isJsArray(env);
Label atLeastOneArg(env);
Label callbackFnHandleHeapObject(env);
Label callbackFnHandleCallable(env);
Label noTypeError(env);
Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
Bind(&isHeapObject);
Branch(IsJsArray(thisValue), &isJsArray, slowPath);
Bind(&isJsArray);
thisLen = GetArrayLength(thisValue);
Branch(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath);
Bind(&atLeastOneArg);
GateRef callbackFnHandle = GetCallArg0(numArgs);
Branch(TaggedIsHeapObject(callbackFnHandle), &callbackFnHandleHeapObject, slowPath);
Bind(&callbackFnHandleHeapObject);
Branch(IsCallable(callbackFnHandle), &callbackFnHandleCallable, slowPath);
Bind(&callbackFnHandleCallable);
GateRef thisLenIsZero = Int32Equal(*thisLen, Int32(0));
GateRef numArgsLessThanTwo = Int64LessThan(numArgs, IntPtr(2));
Branch(BoolAnd(thisLenIsZero, numArgsLessThanTwo), slowPath, &noTypeError);
Bind(&noTypeError);
{
DEFVARIABLE(accumulator, VariableType::JS_ANY(), Undefined());
DEFVARIABLE(k, VariableType::INT32(), Int32(0));
Label updateAccumulator(env);
Label checkForStableJSArray(env);
Branch(Int64Equal(numArgs, IntPtr(2)), &updateAccumulator, slowPath); // 2: provide initialValue param
Bind(&updateAccumulator);
{
accumulator = GetCallArg1(numArgs);
Jump(&checkForStableJSArray);
}
Bind(&checkForStableJSArray);
{
Label isStableJSArray(env);
Label notStableJSArray(env);
Branch(IsStableJSArray(glue, thisValue), &isStableJSArray, &notStableJSArray);
Bind(&isStableJSArray);
{
GateRef argsLength = Int32(4); // 4: «accumulator, kValue, k, thisValue»
NewObjectStubBuilder newBuilder(this);
GateRef argList = newBuilder.NewTaggedArray(glue, argsLength);
Label loopHead(env);
Label next(env);
Label loopEnd(env);
Label loopExit(env);
Jump(&loopHead);
LoopBegin(&loopHead);
{
Branch(Int32LessThan(*k, *thisLen), &next, &loopExit);
Bind(&next);
{
Label updateK(env);
Label notHole(env);
Label changeThisLen(env);
Label updateCallResult(env);
GateRef elements = GetElementsArray(thisValue);
GateRef kValue = GetValueFromTaggedArray(elements, *k);
Branch(TaggedIsHole(kValue), &loopEnd, &notHole);
Bind(&notHole);
{
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator);
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), kValue);
// 2 : parameter location
SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k));
// 3 : parameter location
SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue);
GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET));
GateRef callResult = JSCallDispatch(glue, callbackFnHandle, argsLength, 0,
Circuit::NullGate(), JSCallMode::CALL_THIS_ARGV_WITH_RETURN,
{argsLength, argv, Undefined()});
GateRef newLen = GetLengthOfTaggedArray(elements);
Branch(Int32LessThan(newLen, *thisLen), &changeThisLen, &updateCallResult);
Bind(&changeThisLen);
{
thisLen = newLen;
Jump(&updateCallResult);
}
Bind(&updateCallResult);
{
accumulator = callResult;
Jump(&loopEnd);
}
}
}
}
Bind(&loopEnd);
{
k = Int32Add(*k, Int32(1));
Label isStableJSArray1(env);
Label notStableJSArray1(env);
Branch(IsStableJSArray(glue, thisValue), &isStableJSArray1, &notStableJSArray1);
Bind(&notStableJSArray1);
{
Jump(&loopExit);
}
Bind(&isStableJSArray1);
LoopEnd(&loopHead);
}
Bind(&loopExit);
Jump(&notStableJSArray);
}
Bind(&notStableJSArray);
{
Label finish(env);
Label callRT(env);
Branch(Int32LessThan(*k, *thisLen), &callRT, &finish);
Bind(&callRT);
{
accumulator = CallRuntime(glue, RTSTUB_ID(JSArrayReduceUnStable), { thisValue, thisValue,
IntToTaggedInt(*k), IntToTaggedInt(*thisLen), *accumulator, callbackFnHandle });
Jump(&finish);
}
Bind(&finish);
{
result->WriteVariable(*accumulator);
Jump(exit);
}
}
}
}
}
// Note: unused arguments are reserved for further development
void BuiltinsArrayStubBuilder::Reverse(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
@ -693,8 +950,11 @@ void BuiltinsArrayStubBuilder::Values(GateRef glue, GateRef thisValue,
{
auto env = GetEnvironment();
Label isHeapObject(env);
Label isJsArray(env);
Branch(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath);
Bind(&isHeapObject);
Branch(IsJsArray(thisValue), &isJsArray, slowPath);
Bind(&isJsArray);
ConstantIndex iterClassIdx = ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX;
GateRef iteratorHClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, iterClassIdx);
NewObjectStubBuilder newBuilder(this);
@ -775,7 +1035,6 @@ void BuiltinsArrayStubBuilder::Find(GateRef glue, GateRef thisValue, GateRef num
Jump(exit);
}
void BuiltinsArrayStubBuilder::FindIndex(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath)
{

View File

@ -57,8 +57,14 @@ public:
void Slice(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath);
void Sort(GateRef glue, GateRef thisValue,
GateRef numArgs, Variable *result, Label *exit, Label *slowPath);
void Values(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath);
void Reduce(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath);
void Reverse(GateRef glue, GateRef thisValue, GateRef numArgs,
Variable *result, Label *exit, Label *slowPath);

View File

@ -70,6 +70,7 @@ namespace panda::ecmascript::kungfu {
V(ArrayPop) \
V(ArraySlice) \
V(ArrayValues) \
V(ArrayReduce) \
V(ArrayReverse) \
V(ArrayPush) \
V(ArrayIncludes) \
@ -100,7 +101,8 @@ namespace panda::ecmascript::kungfu {
V(ArrayConstructor)
#define AOT_AND_BUILTINS_STUB_LIST(V) \
V(LocaleCompare)
V(LocaleCompare) \
V(SORT)
#define AOT_BUILTINS_STUB_LIST(V) \
V(SQRT) /* list start and math list start */ \
@ -110,7 +112,6 @@ namespace panda::ecmascript::kungfu {
V(ATAN) \
V(ABS) \
V(FLOOR) /* math list end */ \
V(SORT) \
V(STRINGIFY) \
V(MAP_PROTO_ITERATOR) \
V(SET_PROTO_ITERATOR) \
@ -176,6 +177,7 @@ public:
static bool IsTypedBuiltin(ID builtinId)
{
return (BuiltinsStubCSigns::ID::LocaleCompare == builtinId) ||
(BuiltinsStubCSigns::ID::SORT == builtinId) ||
((BuiltinsStubCSigns::ID::TYPED_BUILTINS_FIRST <= builtinId) &&
(builtinId <= BuiltinsStubCSigns::ID::TYPED_BUILTINS_LAST));
}

View File

@ -290,11 +290,30 @@ DECLARE_BUILTINS(Array##Method)
V(LastIndexOf, JS_ANY) \
V(Pop, JS_ANY) \
V(Slice, JS_POINTER) \
V(Reduce, JS_ANY) \
V(Reverse, JS_POINTER) \
V(Push, JS_ANY) \
V(Values, JS_POINTER) \
V(Includes, JS_ANY)
DECLARE_BUILTINS(SORT)
{
auto env = GetEnvironment();
DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
Label exit(env);
Label slowPath(env);
BuiltinsArrayStubBuilder arrayStubBuilder(this);
arrayStubBuilder.Sort(glue, thisValue, numArgs, &res, &exit, &slowPath);
Bind(&slowPath);
{
auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(SORT));
res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str());
Jump(&exit);
}
Bind(&exit);
Return(*res);
}
BUILTINS_WITH_ARRAY_STUB_BUILDER(DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER)
#undef DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER

View File

@ -1223,6 +1223,20 @@ DEF_CALL_SIGNATURE(BigIntEquals)
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(FastArraySort)
{
// 2 : 2 input parameters
CallSignature fastArraySort("FastArraySort", 0, 2, ArgumentsOrder::DEFAULT_ORDER, VariableType::INT32());
*callSign = fastArraySort;
std::array<VariableType, 2> params = { // 2 : 2 input parameters
VariableType::JS_ANY(),
VariableType::JS_ANY()
};
callSign->SetParameters(params.data());
callSign->SetGCLeafFunction(true);
callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC);
}
DEF_CALL_SIGNATURE(LocaleCompareNoGc)
{
// 4 : 4 input parameters

View File

@ -474,6 +474,7 @@ private:
V(JSHClassFindProtoTransitions) \
V(NumberHelperStringToDouble) \
V(GetStringToListCacheArray) \
V(FastArraySort) \
V(LocaleCompareNoGc) \
V(StringGetStart) \
V(StringGetEnd) \

View File

@ -249,7 +249,7 @@ void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass)
SetConstant(ConstantIndex::JS_MAP_ITERATOR_CLASS_INDEX,
factory->NewEcmaHClass(hClass, JSMapIterator::SIZE, JSType::JS_MAP_ITERATOR, 0)); // 0: no inlined props
SetConstant(ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX,
factory->NewEcmaHClass(hClass, JSArrayIterator::SIZE, JSType::JS_ARRAY_ITERATOR));
factory->NewEcmaHClass(hClass, JSArrayIterator::SIZE, JSType::JS_ARRAY_ITERATOR, 0));
SetConstant(
ConstantIndex::JS_API_ARRAYLIST_ITERATOR_CLASS_INDEX,
factory->NewEcmaHClass(hClass, JSAPIArrayListIterator::SIZE, JSType::JS_API_ARRAYLIST_ITERATOR));

View File

@ -270,6 +270,31 @@ bool JSTaggedValue::Equal(JSThread *thread, const JSHandle<JSTaggedValue> &x, co
return false;
}
uint32_t CountLeadingZeros(uint32_t value, uint32_t bits)
{
if (bits == 1) {
return value ^ 1;
}
uint32_t upper_half = value >> (bits / 2); // 2 : half
uint32_t nextValue = upper_half != 0 ? upper_half : value;
uint32_t add = upper_half != 0 ? 0 : (bits / 2); // 2 : half
uint32_t nextBits = bits == 1 ? 1 : bits / 2; // 2 : half
return CountLeadingZeros(nextValue, nextBits) + add;
}
const uint32_t kPowersOf10[] = {
1,
10,
100,
1000,
10 * 1000,
100 * 1000,
1000 * 1000,
10 * 1000 * 1000,
100 * 1000 * 1000,
1000 * 1000 * 1000,
};
int JSTaggedValue::IntLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
{
ASSERT(x.IsInt() && y.IsInt());
@ -294,15 +319,30 @@ int JSTaggedValue::IntLexicographicCompare(JSTaggedValue x, JSTaggedValue y)
unsignedX = static_cast<uint32_t>(-xValue);
unsignedY = static_cast<uint32_t>(-yValue);
}
int xDigit = log10(unsignedX);
int yDigit = log10(unsignedY);
int res;
uint32_t bits = sizeof(uint32_t) * 8; // 8 : bits
int xLog2 = 31 - CountLeadingZeros(unsignedX, bits); // 31 : Algorithm implementation
int xDigit = ((xLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
xDigit -= unsignedX < kPowersOf10[xDigit];
int yLog2 = 31 - CountLeadingZeros(unsignedY, bits); // 31 : Algorithm implementation
int yDigit = ((yLog2 + 1) * 1233) >> 12; // 1233 、12 : Algorithm implementation
yDigit -= unsignedY < kPowersOf10[yDigit];
int res = 0;
if (xDigit > yDigit) {
unsignedY *= pow(10, xDigit - yDigit); // 10: decimal
// X has fewer digits. We would like to simply scale up X but that
// might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
// be scaled up to 9_000_000_000. So we scale up by the next
// smallest power and scale down Y to drop one digit. It is OK to
// drop one digit from the longer integer since the final digit is
// past the length of the shorter integer.
unsignedY *= kPowersOf10[xDigit - yDigit - 1];
unsignedX /= 10; // 10 : Decimal
res = 1;
}
if (yDigit > xDigit) {
unsignedX *= pow(10, yDigit - xDigit); // 10: decimal
unsignedX *= kPowersOf10[yDigit - xDigit - 1];
unsignedY /= 10; // 10 : Decimal
res = -1;
}
if (unsignedX > unsignedY) {

View File

@ -25,6 +25,7 @@
#include "ecmascript/base/typed_array_helper.h"
#include "ecmascript/builtins/builtins_string_iterator.h"
#include "ecmascript/compiler/builtins/containers_stub_builder.h"
#include "ecmascript/builtins/builtins_array.h"
#include "ecmascript/compiler/call_signature.h"
#include "ecmascript/compiler/ecma_opcode_des.h"
#include "ecmascript/compiler/rt_call_signature.h"
@ -52,6 +53,7 @@
#include "ecmascript/js_set_iterator.h"
#include "ecmascript/js_string_iterator.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_stable_array.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/layout_info.h"
@ -67,6 +69,7 @@
#include "ecmascript/linked_hash_table.h"
#include "ecmascript/builtins/builtins_object.h"
#include "libpandafile/bytecode_instruction-inl.h"
#include "ecmascript/js_tagged_value.h"
#include "macros.h"
#ifdef ARK_SUPPORT_INTL
#include "ecmascript/js_collator.h"
@ -390,6 +393,24 @@ DEF_RUNTIME_STUBS(CheckAndCopyArray)
return receiverHandle->GetElements().GetRawData();
}
DEF_RUNTIME_STUBS(JSArrayReduceUnStable)
{
RUNTIME_STUBS_HEADER(JSArrayReduceUnStable);
JSHandle<JSTaggedValue> thisHandle = GetHArg<JSTaggedValue>(argv, argc, 0); // 0: means the zeroth parameter
JSHandle<JSTaggedValue> thisObjVal = GetHArg<JSTaggedValue>(argv, argc, 1); // 1: means the one parameter
JSTaggedType taggedValueK = GetTArg(argv, argc, 2); // 2: means the two parameter
int64_t k = JSTaggedNumber(JSTaggedValue(taggedValueK)).GetNumber();
JSTaggedType taggedValueLen = GetTArg(argv, argc, 3); // 3: means the three parameter
int64_t len = JSTaggedNumber(JSTaggedValue(taggedValueLen)).GetNumber();
JSMutableHandle<JSTaggedValue> accumulator = JSMutableHandle<JSTaggedValue>(thread,
GetHArg<JSTaggedValue>(argv, argc, 4)); // 4: means the four parameter
JSHandle<JSTaggedValue> callbackFnHandle = GetHArg<JSTaggedValue>(argv, argc, 5); // 5: means the five parameter
JSTaggedValue ret = builtins::BuiltinsArray::ReduceUnStableJSArray(thread, thisHandle, thisObjVal, k, len,
accumulator, callbackFnHandle);
return ret.GetRawData();
}
DEF_RUNTIME_STUBS(JSObjectGrowElementsCapacity)
{
RUNTIME_STUBS_HEADER(JSObjectGrowElementsCapacity);
@ -3004,6 +3025,12 @@ DEF_RUNTIME_STUBS(LocaleCompareWithGc)
options, cacheable).GetRawData();
}
int RuntimeStubs::FastArraySort(JSTaggedType x, JSTaggedType y)
{
DISALLOW_GARBAGE_COLLECTION;
return JSTaggedValue::IntLexicographicCompare(JSTaggedValue(x), JSTaggedValue(y));
}
JSTaggedValue RuntimeStubs::LocaleCompareNoGc(uintptr_t argGlue, JSTaggedType locales, EcmaString *thisHandle,
EcmaString *thatHandle)
{

View File

@ -133,6 +133,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(JSHClassFindProtoTransitions) \
V(NumberHelperStringToDouble) \
V(GetStringToListCacheArray) \
V(FastArraySort) \
V(LocaleCompareNoGc) \
V(StringGetStart) \
V(StringGetEnd) \
@ -161,6 +162,7 @@ using FastCallAotEntryType = JSTaggedValue (*)(uintptr_t glue, uint32_t argc, co
V(NameDictPutIfAbsent) \
V(PropertiesSetValue) \
V(TaggedArraySetValue) \
V(JSArrayReduceUnStable) \
V(CheckAndCopyArray) \
V(NewEcmaHClass) \
V(UpdateLayOutAndAddTransition) \
@ -437,6 +439,7 @@ public:
static JSTaggedValue JSHClassFindProtoTransitions(JSHClass *cls, JSTaggedValue key, JSTaggedValue proto);
static JSTaggedValue NumberHelperStringToDouble(EcmaString *str);
static JSTaggedValue GetStringToListCacheArray(uintptr_t argGlue);
static int FastArraySort(JSTaggedType x, JSTaggedType y);
static JSTaggedValue LocaleCompareNoGc(uintptr_t argGlue, JSTaggedType locales, EcmaString *thisHandle,
EcmaString *thatHandle);
static void ArrayTrim(uintptr_t argGlue, TaggedArray *array, int64_t newLength);

View File

@ -0,0 +1,18 @@
# 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_moduletest_action("arrayreducecase") {
deps = []
}

View File

@ -0,0 +1,46 @@
/*
* 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.
*/
const array1 = [1, 2, 3, 4];
const initialValue = 0;
const sumWithInitial = array1.reduce(
(accumulator, currentValue) => accumulator + currentValue,
initialValue,
);
print(sumWithInitial);
const objects = [{ x: 1 }, { x: 2 }, { x: 3 }];
const sum = objects.reduce(
(accumulator, currentValue) => accumulator + currentValue.x,
0,
);
print(sum); // 6
print([1, 2, , 4].reduce((a, b) => a + b)); // 7
print([1, 2, undefined, 4].reduce((a, b) => a + b)); // NaN
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
};
print(Array.prototype.reduce.call(arrayLike, (x, y) => x + y));
const myArray = ["a", "b", "a", "b", "c", "e", "e", "c", "d", "d", "d", "d"];
const myArrayWithNoDuplicates = myArray.reduce((accumulator, currentValue) => {
if (!accumulator.includes(currentValue)) {
return [...accumulator, currentValue];
}
return accumulator;
}, []);
print(myArrayWithNoDuplicates);

View File

@ -0,0 +1,19 @@
# 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.
10
6
7
NaN
9
a,b,c,e,d

View File

@ -0,0 +1,18 @@
# 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_moduletest_action("arraysortcase") {
deps = []
}

View File

@ -0,0 +1,56 @@
/*
* 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.
*/
const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
print(months);
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
print(array1);
const numberArray1 = new Array(40, 1, 5, 200);
let res1 = numberArray1.sort();
print(res1);
const stringArray = ["Blue", "Humpback", "Beluga"];
const numberArray = [40, 1, 5, 200];
const numericStringArray = ["80", "9", "700"];
const mixedNumericArray = ["80", "9", "700", 40, 1, 5, 200];
function compareNumbers(a, b) {
return a - b;
}
stringArray.join(); // 'Blue,Humpback,Beluga'
stringArray.sort(); // ['Beluga', 'Blue', 'Humpback']
print(stringArray)
numberArray.join(); // '40,1,5,200'
numberArray.sort(); // [1, 200, 40, 5]
numberArray.sort(compareNumbers); // [1, 5, 40, 200]
print(numberArray)
numericStringArray.join(); // '80,9,700'
numericStringArray.sort(); // ['700', '80', '9']
numericStringArray.sort(compareNumbers); // ['9', '80', '700']
print(numericStringArray)
mixedNumericArray.join(); // '80,9,700,40,1,5,200'
mixedNumericArray.sort(); // [1, 200, 40, 5, '700', '80', '9']
mixedNumericArray.sort(compareNumbers); // [1, 5, '9', 40, '80', 200, '700']
print(mixedNumericArray)
print(["a", "c", , "b"].sort()); // ['a', 'b', 'c', empty]
print([, undefined, "a", "b"].sort()); // ["a", "b", undefined, empty]

View File

@ -0,0 +1,22 @@
# 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.
Dec,Feb,Jan,March
1,100000,21,30,4
1,200,40,5
Beluga,Blue,Humpback
1,5,40,200
9,80,700
1,5,9,40,80,200,700
a,b,c,
a,b,,