mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 18:20:04 +00:00
Add fastpath Int32ToString, add singleCharTable in vm
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8ID3Q?from=project-issue Signed-off-by: yaochaonan <yaochaonan@huawei.com> Change-Id: I950f1a8530b22e2be1357054a8fbfec18a09dae0
This commit is contained in:
parent
96162a0358
commit
86555cd737
@ -24,6 +24,7 @@
|
||||
|
||||
#include "ecmascript/base/builtins_base.h"
|
||||
#include "ecmascript/base/string_helper.h"
|
||||
#include "ecmascript/ecma_string_table.h"
|
||||
#include "ecmascript/js_tagged_value-inl.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
|
||||
@ -115,6 +116,57 @@ bool NumberHelper::IsEmptyString(const uint8_t *start, const uint8_t *end)
|
||||
return !NumberHelper::GotoNonspace(&p, end);
|
||||
}
|
||||
|
||||
/*
|
||||
* This Function Translate from number 0-9 to number '0'-'9'
|
||||
* number 10-35 to number 'a'-'z'
|
||||
*/
|
||||
uint32_t NumberHelper::ToCharCode(uint32_t number)
|
||||
{
|
||||
ASSERT(number < 36); // total number of '0'-'9' + 'a' -'z'
|
||||
return number < 10 ? (number + 48): // 48 == '0'; 10: '0' - '9';
|
||||
(number - 10 + 97); // 97 == 'a'; 'a' - 'z'
|
||||
}
|
||||
|
||||
JSTaggedValue NumberHelper::Int32ToString(JSThread *thread, int32_t number, uint32_t radix)
|
||||
{
|
||||
bool isNegative = number < 0;
|
||||
uint32_t n = 0;
|
||||
if (!isNegative) {
|
||||
n = static_cast<uint32_t>(number);
|
||||
if (n < radix) {
|
||||
if (n == 0) {
|
||||
return thread->GlobalConstants()->GetHandledZeroString().GetTaggedValue();
|
||||
}
|
||||
JSHandle<SingleCharTable> singleCharTable(thread->GetEcmaVM()->GetSingleCharTable());
|
||||
return singleCharTable->GetStringFromSingleCharTable(ToCharCode(n));
|
||||
}
|
||||
} else {
|
||||
n = static_cast<uint32_t>(-number);
|
||||
}
|
||||
uint32_t temp = n;
|
||||
uint32_t length = isNegative ? 1 : 0;
|
||||
// calculate length
|
||||
while (temp > 0) {
|
||||
temp = temp / radix;
|
||||
length = length + 1;
|
||||
}
|
||||
std::string buf;
|
||||
buf.resize(length);
|
||||
uint32_t index = length - 1;
|
||||
uint32_t digit = 0;
|
||||
while (n > 0) {
|
||||
digit = n % radix;
|
||||
n /= radix;
|
||||
buf[index] = ToCharCode(digit) + 0X00;
|
||||
index--;
|
||||
}
|
||||
if (isNegative) {
|
||||
ASSERT(index == 0);
|
||||
buf[index] = '-';
|
||||
}
|
||||
return thread->GetEcmaVM()->GetFactory()->NewFromUtf8(buf).GetTaggedValue();
|
||||
}
|
||||
|
||||
JSTaggedValue NumberHelper::DoubleToString(JSThread *thread, double number, int radix)
|
||||
{
|
||||
static constexpr int BUFFER_SIZE = 2240; // 2240: The size of the character array buffer
|
||||
@ -367,7 +419,11 @@ JSHandle<EcmaString> NumberHelper::NumberToString(const JSThread *thread, JSTagg
|
||||
ASSERT(number.IsNumber());
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
if (number.IsInt()) {
|
||||
return factory->NewFromASCII(IntToString(number.GetInt()));
|
||||
int intVal = number.GetInt();
|
||||
if (intVal == 0) {
|
||||
return JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledZeroString());
|
||||
}
|
||||
return factory->NewFromASCII(IntToString(intVal));
|
||||
}
|
||||
|
||||
double d = number.GetDouble();
|
||||
|
@ -108,6 +108,8 @@ public:
|
||||
static JSTaggedValue DoubleToString(JSThread *thread, double number, int radix);
|
||||
static bool IsEmptyString(const uint8_t *start, const uint8_t *end);
|
||||
static JSHandle<EcmaString> IntToEcmaString(const JSThread *thread, int number);
|
||||
static uint32_t ToCharCode(uint32_t number);
|
||||
static JSTaggedValue Int32ToString(JSThread *thread, int32_t number, uint32_t radix);
|
||||
static JSHandle<EcmaString> NumberToString(const JSThread *thread, JSTaggedValue number);
|
||||
static double TruncateDouble(double d);
|
||||
static int64_t DoubleToInt64(double d);
|
||||
|
@ -429,7 +429,9 @@ JSTaggedValue BuiltinsNumber::ToString(EcmaRuntimeCallInfo *argv)
|
||||
double radix = base::DECIMAL;
|
||||
JSHandle<JSTaggedValue> radixValue = GetCallArg(argv, 0);
|
||||
// 5. Else let radixNumber be ToInteger(radix).
|
||||
if (!radixValue->IsUndefined()) {
|
||||
if (radixValue->IsInt()) {
|
||||
radix = radixValue->GetInt();
|
||||
} else if (!radixValue->IsUndefined()) {
|
||||
JSTaggedNumber radixNumber = JSTaggedValue::ToInteger(thread, radixValue);
|
||||
// 6. ReturnIfAbrupt(x).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
@ -452,6 +454,10 @@ JSTaggedValue BuiltinsNumber::ToString(EcmaRuntimeCallInfo *argv)
|
||||
return resultJSHandle.GetTaggedValue();
|
||||
}
|
||||
|
||||
if (value.IsInt()) {
|
||||
return NumberHelper::Int32ToString(thread, value.GetInt(), radix);
|
||||
}
|
||||
|
||||
double valueNumber = value.GetNumber();
|
||||
// If x is NaN, return the String "NaN".
|
||||
if (std::isnan(valueNumber)) {
|
||||
|
@ -214,28 +214,101 @@ HWTEST_F_L0(BuiltinsNumberTest, IsNaN)
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
}
|
||||
|
||||
// new Number(123.456).toString(7)
|
||||
HWTEST_F_L0(BuiltinsNumberTest, ToString)
|
||||
HWTEST_F_L0(BuiltinsNumberTest, ToString1)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
auto ecmaVM = thread->GetEcmaVM();
|
||||
JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
|
||||
|
||||
// new Number(123.456).toString(7)
|
||||
JSHandle<JSFunction> numberObject(env->GetNumberFunction());
|
||||
JSHandle<JSTaggedValue> value(thread, JSTaggedValue(123.456));
|
||||
JSHandle<JSPrimitiveRef> number = thread->GetEcmaVM()->GetFactory()->NewJSPrimitiveRef(numberObject, value);
|
||||
|
||||
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo->SetThis(number.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(7.0));
|
||||
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo1->SetThis(number.GetTaggedValue());
|
||||
ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(7.0));
|
||||
|
||||
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
|
||||
JSTaggedValue result = BuiltinsNumber::ToString(ecmaRuntimeCallInfo);
|
||||
ASSERT_TRUE(result.IsString());
|
||||
JSHandle<EcmaString> res(thread, reinterpret_cast<EcmaString *>(result.GetRawData()));
|
||||
JSHandle<EcmaString> correctResult = factory->NewFromASCII("234.312256641535441");
|
||||
ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res, *correctResult));
|
||||
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
|
||||
JSTaggedValue result1 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo1);
|
||||
ASSERT_TRUE(result1.IsString());
|
||||
JSHandle<EcmaString> res1(thread, reinterpret_cast<EcmaString *>(result1.GetRawData()));
|
||||
JSHandle<EcmaString> correctResult1 = factory->NewFromASCII("234.312256641535441");
|
||||
ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res1, *correctResult1));
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
|
||||
// (15).toString(4)
|
||||
auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo2->SetThis(JSTaggedValue(15));
|
||||
ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue(4));
|
||||
|
||||
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
|
||||
JSTaggedValue result2 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo2);
|
||||
ASSERT_TRUE(result2.IsString());
|
||||
JSHandle<EcmaString> res2(thread, reinterpret_cast<EcmaString *>(result2.GetRawData()));
|
||||
JSHandle<EcmaString> correctResult2 = factory->NewFromASCII("33");
|
||||
ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res2, *correctResult2));
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
|
||||
// (5).toString(8)
|
||||
auto ecmaRuntimeCallInfo3 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo3->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo3->SetThis(JSTaggedValue(5));
|
||||
ecmaRuntimeCallInfo3->SetCallArg(0, JSTaggedValue(8));
|
||||
|
||||
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo3);
|
||||
JSTaggedValue result3 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo3);
|
||||
ASSERT_TRUE(result3.IsString());
|
||||
JSHandle<EcmaString> res3(thread, reinterpret_cast<EcmaString *>(result3.GetRawData()));
|
||||
JSHandle<EcmaString> correctResult3 = factory->NewFromASCII("5");
|
||||
ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res3, *correctResult3));
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
|
||||
// (0).toString(8)
|
||||
auto ecmaRuntimeCallInfo4 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo4->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo4->SetThis(JSTaggedValue(0));
|
||||
ecmaRuntimeCallInfo4->SetCallArg(0, JSTaggedValue(8));
|
||||
|
||||
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo4);
|
||||
JSTaggedValue result4 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo4);
|
||||
ASSERT_TRUE(result4.IsString());
|
||||
JSHandle<EcmaString> res4(thread, reinterpret_cast<EcmaString *>(result4.GetRawData()));
|
||||
JSHandle<EcmaString> correctResult4 = factory->NewFromASCII("0");
|
||||
ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res4, *correctResult4));
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
}
|
||||
HWTEST_F_L0(BuiltinsNumberTest, ToString2)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
// (-50).toString(35)
|
||||
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(-50));
|
||||
ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(35));
|
||||
|
||||
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
|
||||
JSTaggedValue result1 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo1);
|
||||
ASSERT_TRUE(result1.IsString());
|
||||
JSHandle<EcmaString> res1(thread, reinterpret_cast<EcmaString *>(result1.GetRawData()));
|
||||
JSHandle<EcmaString> correctResult1 = factory->NewFromASCII("-1f");
|
||||
ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res1, *correctResult1));
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
|
||||
// (2).toString(2.5)
|
||||
auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
|
||||
ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo2->SetThis(JSTaggedValue(2));
|
||||
ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue(2.5));
|
||||
|
||||
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
|
||||
JSTaggedValue result2 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo2);
|
||||
ASSERT_TRUE(result2.IsString());
|
||||
JSHandle<EcmaString> res2(thread, reinterpret_cast<EcmaString *>(result2.GetRawData()));
|
||||
JSHandle<EcmaString> correctResult2 = factory->NewFromASCII("10");
|
||||
ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res2, *correctResult2));
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "ecmascript/jspandafile/js_pandafile.h"
|
||||
#include "ecmascript/mem/c_string.h"
|
||||
#include "ecmascript/mem/space.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
@ -310,4 +311,18 @@ bool EcmaStringTable::CheckStringTableValidity()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSTaggedValue SingleCharTable::CreateSingleCharTable(const JSThread *thread)
|
||||
{
|
||||
auto table = static_cast<SingleCharTable*>(
|
||||
*thread->GetEcmaVM()->GetFactory()->NewTaggedArray(MAX_ONEBYTE_CHARCODE,
|
||||
JSTaggedValue::Undefined(), MemSpaceType::NON_MOVABLE));
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
table->Set(thread, 0, thread->GlobalConstants()->GetHandledZeroString().GetTaggedValue());
|
||||
for (uint32_t i = 1; i < MAX_ONEBYTE_CHARCODE; ++i) {
|
||||
std::string tmp(1, i + 0X00); // 1: size
|
||||
table->Set(thread, i, factory->NewFromASCIINonMovable(tmp).GetTaggedValue());
|
||||
}
|
||||
return JSTaggedValue(table);
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "ecmascript/mem/c_containers.h"
|
||||
#include "ecmascript/mem/space.h"
|
||||
#include "ecmascript/mem/visitor.h"
|
||||
#include "ecmascript/tagged_array-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
class EcmaString;
|
||||
@ -72,6 +73,21 @@ private:
|
||||
const EcmaVM *vm_{nullptr};
|
||||
friend class SnapshotProcessor;
|
||||
};
|
||||
|
||||
class SingleCharTable : public TaggedArray {
|
||||
public:
|
||||
static SingleCharTable *Cast(TaggedObject *object)
|
||||
{
|
||||
return reinterpret_cast<SingleCharTable*>(object);
|
||||
}
|
||||
static JSTaggedValue CreateSingleCharTable(const JSThread *thread);
|
||||
JSTaggedValue GetStringFromSingleCharTable(int32_t ch)
|
||||
{
|
||||
return Get(ch);
|
||||
}
|
||||
private:
|
||||
static constexpr uint32_t MAX_ONEBYTE_CHARCODE = 128; // 0X00-0X7F
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // ECMASCRIPT_STRING_TABLE_H
|
||||
|
@ -232,6 +232,7 @@ bool EcmaVM::Initialize()
|
||||
thread_->GetCurrentEcmaContext()->LoadStubFile();
|
||||
}
|
||||
|
||||
singleCharTable_ = SingleCharTable::CreateSingleCharTable(thread_);
|
||||
callTimer_ = new FunctionCallTimer();
|
||||
strategy_ = new ThroughputJSObjectResizingStrategy();
|
||||
initialized_ = true;
|
||||
@ -507,6 +508,7 @@ void EcmaVM::Iterate(const RootVisitor &v, const RootRangeVisitor &rv)
|
||||
{
|
||||
rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())),
|
||||
ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize()));
|
||||
v(Root::ROOT_VM, ObjectSlot(ToUintPtr(&singleCharTable_)));
|
||||
if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
|
||||
snapshotEnv_->Iterate(v);
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ enum class PromiseRejectionEvent : uint8_t;
|
||||
class JSPandaFileManager;
|
||||
class JSPandaFile;
|
||||
class EcmaStringTable;
|
||||
class SingleCharTable;
|
||||
class SnapshotEnv;
|
||||
class SnapshotSerialize;
|
||||
class SnapshotProcessor;
|
||||
@ -450,6 +451,12 @@ public:
|
||||
return stringTable_;
|
||||
}
|
||||
|
||||
JSHandle<JSTaggedValue> GetSingleCharTable() const
|
||||
{
|
||||
ASSERT(singleCharTable_ != JSTaggedValue::Hole());
|
||||
return JSHandle<JSTaggedValue>(reinterpret_cast<uintptr_t>(&singleCharTable_));
|
||||
}
|
||||
|
||||
void IncreaseCallDepth()
|
||||
{
|
||||
callDepth_++;
|
||||
@ -501,6 +508,7 @@ private:
|
||||
bool initialized_ {false};
|
||||
GCStats *gcStats_ {nullptr};
|
||||
EcmaStringTable *stringTable_;
|
||||
JSTaggedValue singleCharTable_ {JSTaggedValue::Hole()};
|
||||
|
||||
// VM memory management.
|
||||
std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_;
|
||||
|
@ -70,22 +70,20 @@ std::enable_if_t<std::is_floating_point_v<T>, CString> FloatToCString(T number)
|
||||
template<class T>
|
||||
std::enable_if_t<std::is_integral_v<T>, CString> ToCString(T number)
|
||||
{
|
||||
if (number == 0) {
|
||||
return CString("0");
|
||||
}
|
||||
static constexpr uint32_t BUFF_SIZE = std::numeric_limits<T>::digits10 + 3; // 3: Reserved for sign bit and '\0'.
|
||||
int64_t n = static_cast<int64_t>(number);
|
||||
char buf[BUFF_SIZE];
|
||||
uint32_t position = BUFF_SIZE - 1;
|
||||
buf[position] = '\0';
|
||||
bool isNeg = number < 0;
|
||||
while (number != 0) {
|
||||
if (isNeg) {
|
||||
buf[--position] = static_cast<int8_t>('0' - (number % 10)); // 10 : decimal
|
||||
} else {
|
||||
buf[--position] = static_cast<int8_t>('0' + (number % 10)); // 10 : decimal
|
||||
}
|
||||
number /= 10; // 10 : decimal
|
||||
bool isNeg = true;
|
||||
if (n >= 0) {
|
||||
n = -n;
|
||||
isNeg = false;
|
||||
}
|
||||
do {
|
||||
buf[--position] = static_cast<int8_t>('0' - (n % 10)); // 10 : decimal
|
||||
n /= 10; // 10 : decimal
|
||||
} while (n);
|
||||
if (isNeg) {
|
||||
buf[--position] = '-';
|
||||
}
|
||||
|
@ -655,6 +655,7 @@ private:
|
||||
friend class EcmaString;
|
||||
friend class SnapshotProcessor;
|
||||
friend class TSManager;
|
||||
friend class SingleCharTable;
|
||||
void InitObjectFields(const TaggedObject *object);
|
||||
|
||||
JSThread *thread_ {nullptr};
|
||||
|
Loading…
Reference in New Issue
Block a user