Reason:Add SlicedString to optimize string.substring

Description:Add SlicedString to optimize string.substring
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I7XUDH?from=project-issue

Signed-off-by: wupengyong <wupengyong@huawei.com>
Change-Id: I4bb78eb5f66c480e160567704bca53c200dde74c
This commit is contained in:
wupengyong 2023-09-01 17:13:25 +08:00
parent 09412f71ca
commit fa4b637a68
39 changed files with 863 additions and 289 deletions

View File

@ -369,7 +369,8 @@ JSTaggedValue JsonStringifier::SerializeJSONProperty(const JSHandle<JSTaggedValu
// If Type(value) is String, return QuoteJSONString(value).
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING: {
case JSType::TREE_STRING:
case JSType::SLICED_STRING: {
JSHandle<EcmaString> strHandle = JSHandle<EcmaString>(valHandle);
auto string = JSHandle<EcmaString>(thread_,
EcmaStringAccessor::Flatten(thread_->GetEcmaVM(), strHandle));

View File

@ -1519,6 +1519,9 @@ JSTaggedValue BuiltinsString::Substring(EcmaRuntimeCallInfo *argv)
int32_t from = std::min(start, end);
int32_t to = std::max(start, end);
int32_t len = to - from;
if (static_cast<uint32_t>(len) >= SlicedString::MIN_SLICED_ECMASTRING_LENGTH) {
return JSTaggedValue(EcmaStringAccessor::GetSlicedString(thread->GetEcmaVM(), thisHandle, from, len));
}
return JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), thisHandle, from, len));
}

View File

@ -19,7 +19,7 @@
#include "ecmascript/compiler/new_object_stub_builder.h"
namespace panda::ecmascript::kungfu {
GateRef BuiltinsStringStubBuilder::StringAt(GateRef obj, GateRef index)
GateRef BuiltinsStringStubBuilder::StringAt(const StringInfoGateRef &stringInfoGate, GateRef index)
{
auto env = GetEnvironment();
Label entry(env);
@ -32,8 +32,8 @@ GateRef BuiltinsStringStubBuilder::StringAt(GateRef obj, GateRef index)
Label doIntOp(env);
Label leftIsNumber(env);
Label rightIsNumber(env);
GateRef dataUtf16 = GetNormalStringData(obj);
Branch(IsUtf16String(obj), &isUtf16, &isUtf8);
GateRef dataUtf16 = GetNormalStringData(stringInfoGate);
Branch(IsUtf16String(stringInfoGate.GetString()), &isUtf16, &isUtf8);
Bind(&isUtf16);
{
result = ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(dataUtf16,
@ -52,7 +52,8 @@ GateRef BuiltinsStringStubBuilder::StringAt(GateRef obj, GateRef index)
return ret;
}
GateRef BuiltinsStringStubBuilder::CreateFromEcmaString(GateRef glue, GateRef obj, GateRef index)
GateRef BuiltinsStringStubBuilder::CreateFromEcmaString(GateRef glue, GateRef index,
const StringInfoGateRef &stringInfoGate)
{
auto env = GetEnvironment();
Label entry(env);
@ -65,8 +66,8 @@ GateRef BuiltinsStringStubBuilder::CreateFromEcmaString(GateRef glue, GateRef ob
Label isUtf16(env);
Label isUtf8(env);
Label allocString(env);
GateRef dataUtf = GetNormalStringData(obj);
Branch(IsUtf16String(obj), &isUtf16, &isUtf8);
GateRef dataUtf = GetNormalStringData(stringInfoGate);
Branch(IsUtf16String(stringInfoGate.GetString()), &isUtf16, &isUtf8);
Bind(&isUtf16);
{
GateRef dataAddr = PtrAdd(dataUtf, PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))));
@ -121,7 +122,8 @@ GateRef BuiltinsStringStubBuilder::CreateFromEcmaString(GateRef glue, GateRef ob
return ret;
}
GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue, GateRef from,
GateRef len, const StringInfoGateRef &stringInfoGate)
{
auto env = GetEnvironment();
Label entry(env);
@ -148,7 +150,7 @@ GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue
Branch(Int32Equal(from, Int32(0)), &fromEqualZero, &next);
Bind(&fromEqualZero);
{
GateRef thisLen = GetLengthFromString(thisValue);
GateRef thisLen = stringInfoGate.GetLength();
Branch(Int32Equal(len, thisLen), &exit, &next);
}
Bind(&next);
@ -156,12 +158,12 @@ GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue
Branch(IsUtf8String(thisValue), &isUtf8, &isUtf16);
Bind(&isUtf8);
{
result = FastSubUtf8String(glue, thisValue, from, len);
result = FastSubUtf8String(glue, from, len, stringInfoGate);
Jump(&exit);
}
Bind(&isUtf16);
{
result = FastSubUtf16String(glue, thisValue, from, len);
result = FastSubUtf16String(glue, from, len, stringInfoGate);
Jump(&exit);
}
}
@ -172,7 +174,8 @@ GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue
return ret;
}
GateRef BuiltinsStringStubBuilder::FastSubUtf8String(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
GateRef BuiltinsStringStubBuilder::FastSubUtf8String(GateRef glue, GateRef from, GateRef len,
const StringInfoGateRef &stringInfoGate)
{
auto env = GetEnvironment();
Label entry(env);
@ -187,7 +190,7 @@ GateRef BuiltinsStringStubBuilder::FastSubUtf8String(GateRef glue, GateRef thisV
Bind(&afterNew);
{
GateRef dst = PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET));
GateRef source = PtrAdd(GetNormalStringData(thisValue), ZExtInt32ToPtr(from));
GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), ZExtInt32ToPtr(from));
CopyChars(glue, dst, source, len, IntPtr(sizeof(uint8_t)), VariableType::INT8());
Jump(&exit);
}
@ -197,7 +200,8 @@ GateRef BuiltinsStringStubBuilder::FastSubUtf8String(GateRef glue, GateRef thisV
return ret;
}
GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef from, GateRef len,
const StringInfoGateRef &stringInfoGate)
{
auto env = GetEnvironment();
Label entry(env);
@ -211,7 +215,7 @@ GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef this
Label isUtf16Next(env);
GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
GateRef source = PtrAdd(GetNormalStringData(thisValue), fromOffset);
GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
GateRef canBeCompressed = CanBeCompressed(source, len, true);
NewObjectStubBuilder newBuilder(this);
newBuilder.SetParameters(glue, 0);
@ -227,7 +231,7 @@ GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef this
}
Bind(&afterNew);
{
GateRef source1 = PtrAdd(GetNormalStringData(thisValue), fromOffset);
GateRef source1 = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
GateRef dst = PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET));
Branch(canBeCompressed, &isUtf8Next, &isUtf16Next);
Bind(&isUtf8Next);
@ -503,7 +507,19 @@ GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhsData, bool lhsIsUtf8
return ret;
}
GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhs, GateRef rhs, GateRef pos)
void BuiltinsStringStubBuilder::StoreParent(GateRef glue, GateRef object, GateRef parent)
{
Store(VariableType::JS_POINTER(), glue, object, IntPtr(SlicedString::PARENT_OFFSET), parent);
}
void BuiltinsStringStubBuilder::StoreStartIndex(GateRef glue, GateRef object, GateRef startIndex)
{
Store(VariableType::INT32(), glue, object, IntPtr(SlicedString::STARTINDEX_OFFSET), startIndex);
}
GateRef BuiltinsStringStubBuilder::StringIndexOf(const StringInfoGateRef &lStringInfoGate,
const StringInfoGateRef &rStringInfoGate, GateRef pos)
{
auto env = GetEnvironment();
Label entry(env);
@ -521,8 +537,8 @@ GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhs, GateRef rhs, GateR
Label rhsIsUtf16(env);
Label posRMaxNotGreaterLhs(env);
GateRef lhsCount = GetLengthFromString(lhs);
GateRef rhsCount = GetLengthFromString(rhs);
GateRef lhsCount = lStringInfoGate.GetLength();
GateRef rhsCount = rStringInfoGate.GetLength();
Branch(Int32GreaterThan(pos, lhsCount), &exit, &nextCount);
Bind(&nextCount);
@ -550,14 +566,14 @@ GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhs, GateRef rhs, GateR
GateRef posRMax = Int32Add(*posTag, rhsCount);
Branch(Int32GreaterThan(posRMax, lhsCount), &exit, &posRMaxNotGreaterLhs);
Bind(&posRMaxNotGreaterLhs);
GateRef rhsData = GetNormalStringData(rhs);
GateRef lhsData = GetNormalStringData(lhs);
Branch(IsUtf8String(rhs), &rhsIsUtf8, &rhsIsUtf16);
GateRef rhsData = GetNormalStringData(rStringInfoGate);
GateRef lhsData = GetNormalStringData(lStringInfoGate);
Branch(IsUtf8String(rStringInfoGate.GetString()), &rhsIsUtf8, &rhsIsUtf16);
Bind(&rhsIsUtf8);
{
Label lhsIsUtf8(env);
Label lhsIsUtf16(env);
Branch(IsUtf8String(lhs), &lhsIsUtf8, &lhsIsUtf16);
Branch(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
Bind(&lhsIsUtf8);
{
result = StringIndexOf(lhsData, true, rhsData, true, *posTag, max, rhsCount);
@ -573,7 +589,7 @@ GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhs, GateRef rhs, GateR
{
Label lhsIsUtf8(env);
Label lhsIsUtf16(env);
Branch(IsUtf8String(lhs), &lhsIsUtf8, &lhsIsUtf16);
Branch(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
Bind(&lhsIsUtf8);
{
result = StringIndexOf(lhsData, true, rhsData, false, *posTag, max, rhsCount);
@ -594,4 +610,49 @@ GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhs, GateRef rhs, GateR
env->SubCfgExit();
return ret;
}
void FlatStringStubBuilder::FlattenString(GateRef glue, GateRef str, Label *fastPath)
{
auto env = GetEnvironment();
Label notLineString(env);
Label exit(env);
length_ = GetLengthFromString(str);
Branch(BoolOr(IsLineString(str), IsConstantString(str)), &exit, &notLineString);
Bind(&notLineString);
{
Label isTreeString(env);
Label notTreeString(env);
Label isSlicedString(env);
Branch(IsTreeString(str), &isTreeString, &notTreeString);
Bind(&isTreeString);
{
Label isFlat(env);
Label notFlat(env);
Branch(TreeStringIsFlat(str), &isFlat, &notFlat);
Bind(&isFlat);
{
flatString_.WriteVariable(GetFirstFromTreeString(str));
Jump(fastPath);
}
Bind(&notFlat);
{
flatString_.WriteVariable(CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str }));
Jump(fastPath);
}
}
Bind(&notTreeString);
Branch(IsSlicedString(str), &isSlicedString, &exit);
Bind(&isSlicedString);
{
flatString_.WriteVariable(GetParentFromSlicedString(str));
startIndex_.WriteVariable(GetStartIndexFromSlicedString(str));
Jump(fastPath);
}
}
Bind(&exit);
{
flatString_.WriteVariable(str);
Jump(fastPath);
}
}
} // namespace panda::ecmascript::kungfu

View File

@ -18,6 +18,9 @@
#include "ecmascript/compiler/stub_builder-inl.h"
namespace panda::ecmascript::kungfu {
class FlatStringStubBuilder;
struct StringInfoGateRef;
class BuiltinsStringStubBuilder : public StubBuilder {
public:
explicit BuiltinsStringStubBuilder(StubBuilder *parent)
@ -27,21 +30,90 @@ public:
NO_COPY_SEMANTIC(BuiltinsStringStubBuilder);
void GenerateCircuit() override {}
GateRef StringAt(GateRef obj, GateRef index);
GateRef FastSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len);
GateRef FastSubUtf8String(GateRef glue, GateRef thisValue, GateRef from, GateRef len);
GateRef FastSubUtf16String(GateRef glue, GateRef thisValue, GateRef from, GateRef len);
GateRef StringAt(const StringInfoGateRef &stringInfoGate, GateRef index);
GateRef FastSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len,
const StringInfoGateRef &stringInfoGate);
GateRef FastSubUtf8String(GateRef glue, GateRef from, GateRef len, const StringInfoGateRef &stringInfoGate);
GateRef FastSubUtf16String(GateRef glue, GateRef from, GateRef len, const StringInfoGateRef &stringInfoGate);
void CopyChars(GateRef glue, GateRef dst, GateRef source, GateRef sourceLength, GateRef size, VariableType type);
void CopyUtf16AsUtf8(GateRef glue, GateRef src, GateRef dst, GateRef sourceLength);
GateRef StringIndexOf(GateRef lhsData, bool lhsIsUtf8, GateRef rhsData, bool rhsIsUtf8,
GateRef pos, GateRef max, GateRef rhsCount);
GateRef StringIndexOf(GateRef lhs, GateRef rhs, GateRef pos);
GateRef CreateFromEcmaString(GateRef glue, GateRef obj, GateRef index);
GateRef StringIndexOf(const StringInfoGateRef &lStringInfoGate,
const StringInfoGateRef &rStringInfoGate, GateRef pos);
GateRef CreateFromEcmaString(GateRef glue, GateRef index, const StringInfoGateRef &stringInfoGate);
void StoreParent(GateRef glue, GateRef object, GateRef parent);
void StoreStartIndex(GateRef glue, GateRef object, GateRef startIndex);
private:
GateRef CanBeCompressed(GateRef utf16Data, GateRef utf16Len, bool isUtf16);
GateRef GetUtf16Data(GateRef stringData, GateRef index);
GateRef IsASCIICharacter(GateRef data);
GateRef GetUtf8Data(GateRef stringData, GateRef index);
};
class FlatStringStubBuilder : public StubBuilder {
public:
explicit FlatStringStubBuilder(StubBuilder *parent)
: StubBuilder(parent) {}
~FlatStringStubBuilder() override = default;
NO_MOVE_SEMANTIC(FlatStringStubBuilder);
NO_COPY_SEMANTIC(FlatStringStubBuilder);
void GenerateCircuit() override {}
void FlattenString(GateRef glue, GateRef str, Label *fastPath);
GateRef GetParentFromSlicedString(GateRef string)
{
GateRef offset = IntPtr(SlicedString::PARENT_OFFSET);
return Load(VariableType::JS_POINTER(), string, offset);
}
GateRef GetStartIndexFromSlicedString(GateRef string)
{
GateRef offset = IntPtr(SlicedString::STARTINDEX_OFFSET);
return Load(VariableType::INT32(), string, offset);
}
GateRef GetFlatString()
{
return flatString_.ReadVariable();
}
GateRef GetStartIndex()
{
return startIndex_.ReadVariable();
}
GateRef GetLength()
{
return length_;
}
private:
Variable flatString_ { GetEnvironment(), VariableType::JS_POINTER(), NextVariableId(), Undefined() };
Variable startIndex_ { GetEnvironment(), VariableType::INT32(), NextVariableId(), Int32(0) };
GateRef length_ { Circuit::NullGate() };
};
struct StringInfoGateRef {
GateRef string_ { Circuit::NullGate() };
GateRef startIndex_ { Circuit::NullGate() };
GateRef length_ { Circuit::NullGate() };
StringInfoGateRef(FlatStringStubBuilder *flatString) : string_(flatString->GetFlatString()),
startIndex_(flatString->GetStartIndex()),
length_(flatString->GetLength()) {}
GateRef GetString() const
{
return string_;
}
GateRef GetStartIndex() const
{
return startIndex_;
}
GateRef GetLength() const
{
return length_;
}
};
} // namespace panda::ecmascript::kungfu
#endif // ECMASCRIPT_COMPILER_BUILTINS_STRING_STUB_BUILDER_H

View File

@ -174,10 +174,10 @@ DECLARE_BUILTINS(CharCodeAt)
Branch(IsString(thisValue), &isString, &slowPath);
Bind(&isString);
{
DEFVARIABLE(thisFlat, VariableType::JS_POINTER(), thisValue);
FlattenString(thisValue, &thisFlat, &flattenFastPath, &slowPath);
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
Bind(&flattenFastPath);
GateRef thisLen = GetLengthFromString(*thisFlat);
GateRef thisLen = GetLengthFromString(thisValue);
Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
Bind(&posTagNotUndefined);
{
@ -201,7 +201,8 @@ DECLARE_BUILTINS(CharCodeAt)
Bind(&posNotLessZero);
{
BuiltinsStringStubBuilder stringBuilder(this);
res = IntToTaggedPtr(stringBuilder.StringAt(*thisFlat, *pos));
StringInfoGateRef stringInfoGate(&thisFlat);
res = IntToTaggedPtr(stringBuilder.StringAt(stringInfoGate, *pos));
Jump(&exit);
}
}
@ -292,14 +293,16 @@ DECLARE_BUILTINS(IndexOf)
}
Bind(&nextCount);
{
DEFVARIABLE(thisFlat, VariableType::JS_POINTER(), thisValue);
DEFVARIABLE(searchFlat, VariableType::JS_POINTER(), searchTag);
FlattenString(thisValue, &thisFlat, &flattenFastPath, &slowPath);
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
Bind(&flattenFastPath);
FlattenString(searchTag, &searchFlat, &flattenFastPath1, &slowPath);
FlatStringStubBuilder searchFlat(this);
searchFlat.FlattenString(glue, searchTag, &flattenFastPath1);
Bind(&flattenFastPath1);
BuiltinsStringStubBuilder stringBuilder(this);
GateRef resPos = stringBuilder.StringIndexOf(*thisFlat, *searchFlat, *pos);
StringInfoGateRef thisStringInfoGate(&thisFlat);
StringInfoGateRef searchStringInfoGate(&searchFlat);
GateRef resPos = stringBuilder.StringIndexOf(thisStringInfoGate, searchStringInfoGate, *pos);
Branch(Int32GreaterThanOrEqual(resPos, Int32(0)), &resPosGreaterZero, &exit);
Bind(&resPosGreaterZero);
{
@ -362,6 +365,8 @@ DECLARE_BUILTINS(Substring)
Label startNotGreatEnd(env);
Label thisIsHeapobject(env);
Label flattenFastPath(env);
Label sliceString(env);
Label fastSubstring(env);
Branch(TaggedIsUndefinedOrNull(thisValue), &slowPath, &objNotUndefinedAndNull);
Bind(&objNotUndefinedAndNull);
@ -465,12 +470,22 @@ DECLARE_BUILTINS(Substring)
Bind(&countRes);
{
GateRef len = Int32Sub(*to, *from);
DEFVARIABLE(thisFlat, VariableType::JS_POINTER(), thisValue);
FlattenString(thisValue, &thisFlat, &flattenFastPath, &slowPath);
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
Bind(&flattenFastPath);
{
Branch(Int32GreaterThanOrEqual(len, Int32(SlicedString::MIN_SLICED_ECMASTRING_LENGTH)),
&sliceString, &fastSubstring);
Bind(&sliceString);
{
NewObjectStubBuilder newBuilder(this);
newBuilder.SetParameters(glue, 0);
newBuilder.AllocSlicedStringObject(&res, &exit, *from, len, &thisFlat);
}
Bind(&fastSubstring);
BuiltinsStringStubBuilder stringBuilder(this);
res = stringBuilder.FastSubString(glue, *thisFlat, *from, len);
StringInfoGateRef stringInfoGate(&thisFlat);
res = stringBuilder.FastSubString(glue, thisValue, *from, len, stringInfoGate);
Jump(&exit);
}
}
@ -516,10 +531,10 @@ DECLARE_BUILTINS(CharAt)
Branch(IsString(thisValue), &isString, &slowPath);
Bind(&isString);
{
DEFVARIABLE(thisFlat, VariableType::JS_POINTER(), thisValue);
FlattenString(thisValue, &thisFlat, &flattenFastPath, &slowPath);
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
Bind(&flattenFastPath);
GateRef thisLen = GetLengthFromString(*thisFlat);
GateRef thisLen = GetLengthFromString(thisValue);
Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
Bind(&posTagNotUndefined);
{
@ -543,7 +558,8 @@ DECLARE_BUILTINS(CharAt)
Bind(&posNotLessZero);
{
BuiltinsStringStubBuilder stringBuilder(this);
res = stringBuilder.CreateFromEcmaString(glue, *thisFlat, *pos);
StringInfoGateRef stringInfoGate(&thisFlat);
res = stringBuilder.CreateFromEcmaString(glue, *pos, stringInfoGate);
Jump(&exit);
}
}

View File

@ -910,6 +910,12 @@ GateRef CircuitBuilder::IsTreeString(GateRef obj)
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::TREE_STRING)));
}
GateRef CircuitBuilder::IsSlicedString(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::SLICED_STRING)));
}
GateRef CircuitBuilder::TreeStringIsFlat(GateRef string)
{
GateRef second = GetSecondFromTreeString(string);

View File

@ -599,6 +599,7 @@ public:
inline GateRef BothAreString(GateRef x, GateRef y);
inline GateRef GetObjectSizeFromHClass(GateRef hClass);
inline GateRef IsTreeString(GateRef obj);
inline GateRef IsSlicedString(GateRef obj);
inline GateRef TreeStringIsFlat(GateRef string);
inline GateRef GetFirstFromTreeString(GateRef string);
inline GateRef GetSecondFromTreeString(GateRef string);

View File

@ -893,12 +893,17 @@ void JsProxyCallInternalStubBuilder::GenerateCircuit()
void GetCharFromEcmaStringStubBuilder::GenerateCircuit()
{
auto env = GetEnvironment();
GateRef glue = PtrArgument(0);
GateRef str = TaggedArgument(1);
GateRef index = Int32Argument(2);
Label flattenFastPath(env);
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, str, &flattenFastPath);
Bind(&flattenFastPath);
BuiltinsStringStubBuilder builder(this);
GateRef result = builder.CreateFromEcmaString(glue, str, index);
StringInfoGateRef stringInfoGate(&thisFlat);
GateRef result = builder.CreateFromEcmaString(glue, index, stringInfoGate);
Return(result);
}

View File

@ -16,6 +16,7 @@
#include "ecmascript/compiler/new_object_stub_builder.h"
#include "ecmascript/compiler/stub_builder-inl.h"
#include "ecmascript/ecma_string.h"
#include "ecmascript/global_env.h"
#include "ecmascript/global_env_constants.h"
#include "ecmascript/js_arguments.h"
@ -425,6 +426,29 @@ void NewObjectStubBuilder::AllocLineStringObject(Variable *result, Label *exit,
Jump(exit);
}
void NewObjectStubBuilder::AllocSlicedStringObject(Variable *result, Label *exit, GateRef from, GateRef length,
FlatStringStubBuilder *flatString)
{
auto env = GetEnvironment();
size_ = AlignUp(IntPtr(SlicedString::SIZE), IntPtr(static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)));
Label afterAllocate(env);
AllocateInYoung(result, &afterAllocate);
Bind(&afterAllocate);
GateRef stringClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_,
ConstantIndex::SLICED_STRING_CLASS_INDEX);
StoreHClass(glue_, result->ReadVariable(), stringClass);
GateRef mixLength = Load(VariableType::INT32(), flatString->GetFlatString(), IntPtr(EcmaString::MIX_LENGTH_OFFSET));
GateRef isCompressed = Int32And(Int32(EcmaString::STRING_COMPRESSED_BIT), mixLength);
SetLength(glue_, result->ReadVariable(), length, isCompressed);
SetRawHashcode(glue_, result->ReadVariable(), Int32(0));
BuiltinsStringStubBuilder builtinsStringStubBuilder(this);
builtinsStringStubBuilder.StoreParent(glue_, result->ReadVariable(), flatString->GetFlatString());
builtinsStringStubBuilder.StoreStartIndex(glue_, result->ReadVariable(),
Int32Add(from, flatString->GetStartIndex()));
Jump(exit);
}
GateRef NewObjectStubBuilder::FastNewThisObject(GateRef glue, GateRef ctor)
{

View File

@ -16,6 +16,7 @@
#ifndef ECMASCRIPT_COMPILER_NEW_OBJECT_STUB_BUILDER_H
#define ECMASCRIPT_COMPILER_NEW_OBJECT_STUB_BUILDER_H
#include "ecmascript/compiler/builtins/builtins_string_stub_builder.h"
#include "ecmascript/compiler/profiler_operation.h"
#include "ecmascript/compiler/stub_builder.h"
@ -51,6 +52,8 @@ public:
void NewArgumentsList(Variable *result, Label *exit, GateRef sp, GateRef startIdx, GateRef numArgs);
void NewArgumentsObj(Variable *result, Label *exit, GateRef argumentsList, GateRef numArgs);
void AllocLineStringObject(Variable *result, Label *exit, GateRef length, bool compressed);
void AllocSlicedStringObject(Variable *result, Label *exit, GateRef from, GateRef length,
FlatStringStubBuilder *flatString);
void HeapAlloc(Variable *result, Label *exit, RegionSpaceFlag spaceType);
void NewJSArrayLiteral(Variable *result, Label *exit, RegionSpaceFlag spaceType, GateRef obj, GateRef hclass,
bool isEmptyArray);

View File

@ -1132,6 +1132,12 @@ inline GateRef StubBuilder::IsLineString(GateRef obj)
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::LINE_STRING)));
}
inline GateRef StubBuilder::IsSlicedString(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
return Int32Equal(objectType, Int32(static_cast<int32_t>(JSType::SLICED_STRING)));
}
inline GateRef StubBuilder::IsConstantString(GateRef obj)
{
GateRef objectType = GetObjectType(LoadHClass(obj));
@ -2380,6 +2386,13 @@ inline void StubBuilder::SetLength(GateRef glue, GateRef str, GateRef length, bo
Store(VariableType::INT32(), glue, str, IntPtr(EcmaString::MIX_LENGTH_OFFSET), mixLength);
}
inline void StubBuilder::SetLength(GateRef glue, GateRef str, GateRef length, GateRef isCompressed)
{
GateRef len = Int32LSL(length, Int32(2));
GateRef mixLength = Int32Or(len, isCompressed);
Store(VariableType::INT32(), glue, str, IntPtr(EcmaString::MIX_LENGTH_OFFSET), mixLength);
}
inline void StubBuilder::SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode)
{
Store(VariableType::INT32(), glue, str, IntPtr(EcmaString::HASHCODE_OFFSET), rawHashcode);

View File

@ -17,6 +17,7 @@
#include "ecmascript/compiler/assembler_module.h"
#include "ecmascript/compiler/access_object_stub_builder.h"
#include "ecmascript/compiler/builtins/builtins_string_stub_builder.h"
#include "ecmascript/compiler/interpreter_stub.h"
#include "ecmascript/compiler/llvm_ir_builder.h"
#include "ecmascript/compiler/new_object_stub_builder.h"
@ -1312,6 +1313,7 @@ GateRef StubBuilder::StringToElementIndex(GateRef glue, GateRef string)
DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
Label greatThanZero(env);
Label inRange(env);
Label flattenFastPath(env);
auto len = GetLengthFromString(string);
Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
Bind(&greatThanZero);
@ -1323,8 +1325,12 @@ GateRef StubBuilder::StringToElementIndex(GateRef glue, GateRef string)
Branch(isUtf16String, &exit, &isUtf8);
Bind(&isUtf8);
{
GateRef dataUtf8 = GetNormalStringData(FlattenString(glue, string));
DEFVARIABLE(c, VariableType::INT32(), Int32(0));
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, string, &flattenFastPath);
Bind(&flattenFastPath);
StringInfoGateRef stringInfoGate(&thisFlat);
GateRef dataUtf8 = GetNormalStringData(stringInfoGate);
c = ZExtInt8ToInt32(Load(VariableType::INT8(), dataUtf8));
Label isDigitZero(env);
Label notDigitZero(env);
@ -5697,6 +5703,7 @@ GateRef StubBuilder::TryStringOrSymbolToElementIndex(GateRef glue, GateRef key)
Label greatThanZero(env);
Label inRange(env);
Label flattenFastPath(env);
auto len = GetLengthFromString(key);
Branch(Int32Equal(len, Int32(0)), &exit, &greatThanZero);
Bind(&greatThanZero);
@ -5704,10 +5711,14 @@ GateRef StubBuilder::TryStringOrSymbolToElementIndex(GateRef glue, GateRef key)
Bind(&inRange);
{
Label isUtf8(env);
DEFVARIABLE(c, VariableType::INT32(), Int32(0));
Branch(IsUtf16String(key), &exit, &isUtf8);
Bind(&isUtf8);
GateRef data = GetNormalStringData(FlattenString(glue, key));
DEFVARIABLE(c, VariableType::INT32(), Int32(0));
FlatStringStubBuilder thisFlat(this);
thisFlat.FlattenString(glue, key, &flattenFastPath);
Bind(&flattenFastPath);
StringInfoGateRef stringInfoGate(&thisFlat);
GateRef data = GetNormalStringData(stringInfoGate);
c = ZExtInt8ToInt32(Load(VariableType::INT8(), data));
Label isDigitZero(env);
Label notDigitZero(env);
@ -5922,38 +5933,7 @@ void StubBuilder::Assert(int messageId, int line, GateRef glue, GateRef conditio
}
}
GateRef StubBuilder::FlattenString(GateRef glue, GateRef str)
{
auto env = GetEnvironment();
Label entry(env);
env->SubCfgEntry(&entry);
Label exit(env);
DEFVARIABLE(result, VariableType::JS_POINTER(), str);
Label isTreeString(env);
Branch(IsTreeString(str), &isTreeString, &exit);
Bind(&isTreeString);
{
Label isFlat(env);
Label notFlat(env);
Branch(TreeStringIsFlat(str), &isFlat, &notFlat);
Bind(&isFlat);
{
result = GetFirstFromTreeString(str);
Jump(&exit);
}
Bind(&notFlat);
{
result = CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str });
Jump(&exit);
}
}
Bind(&exit);
auto ret = *result;
env->SubCfgExit();
return ret;
}
GateRef StubBuilder::GetNormalStringData(GateRef str)
GateRef StubBuilder::GetNormalStringData(const StringInfoGateRef &stringInfoGate)
{
auto env = GetEnvironment();
Label entry(env);
@ -5961,18 +5941,31 @@ GateRef StubBuilder::GetNormalStringData(GateRef str)
Label exit(env);
Label isConstantString(env);
Label isLineString(env);
Label isUtf8(env);
Label isUtf16(env);
DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
Branch(IsConstantString(str), &isConstantString, &isLineString);
Branch(IsConstantString(stringInfoGate.GetString()), &isConstantString, &isLineString);
Bind(&isConstantString);
{
GateRef address = PtrAdd(str, IntPtr(ConstantString::CONSTANT_DATA_OFFSET));
result = Load(VariableType::JS_ANY(), address, IntPtr(0));
GateRef address = PtrAdd(stringInfoGate.GetString(), IntPtr(ConstantString::CONSTANT_DATA_OFFSET));
result = PtrAdd(Load(VariableType::JS_ANY(), address, IntPtr(0)), ZExtInt32ToPtr(stringInfoGate.GetStartIndex()));
Jump(&exit);
}
Bind(&isLineString);
{
result = PtrAdd(str, IntPtr(LineEcmaString::DATA_OFFSET));
Jump(&exit);
GateRef data = PtrAdd(stringInfoGate.GetString(), IntPtr(LineEcmaString::DATA_OFFSET));
Branch(IsUtf8String(stringInfoGate.GetString()), &isUtf8, &isUtf16);
Bind(&isUtf8);
{
result = PtrAdd(data, ZExtInt32ToPtr(stringInfoGate.GetStartIndex()));
Jump(&exit);
}
Bind(&isUtf16);
{
GateRef offset = PtrMul(ZExtInt32ToPtr(stringInfoGate.GetStartIndex()), IntPtr(sizeof(uint16_t)));
result = PtrAdd(data, offset);
Jump(&exit);
}
}
Bind(&exit);
auto ret = *result;
@ -5980,35 +5973,6 @@ GateRef StubBuilder::GetNormalStringData(GateRef str)
return ret;
}
void StubBuilder::FlattenString(GateRef str, Variable *flatStr, Label *fastPath, Label *slowPath)
{
auto env = GetEnvironment();
Label notLineString(env);
Label exit(env);
DEFVARIABLE(result, VariableType::JS_POINTER(), str);
Branch(BoolOr(IsLineString(str), IsConstantString(str)), &exit, &notLineString);
Bind(&notLineString);
{
Label isTreeString(env);
Branch(IsTreeString(str), &isTreeString, &exit);
Bind(&isTreeString);
{
Label isFlat(env);
Branch(TreeStringIsFlat(str), &isFlat, slowPath);
Bind(&isFlat);
{
result = GetFirstFromTreeString(str);
Jump(&exit);
}
}
}
Bind(&exit);
{
flatStr->WriteVariable(*result);
Jump(fastPath);
}
}
GateRef StubBuilder::ToNumber(GateRef glue, GateRef tagged)
{
auto env = GetEnvironment();

View File

@ -23,6 +23,7 @@
#include "ecmascript/compiler/variable_type.h"
namespace panda::ecmascript::kungfu {
struct StringInfoGateRef;
using namespace panda::ecmascript;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DEFVARIABLE(varname, type, val) Variable varname(GetEnvironment(), type, NextVariableId(), val)
@ -306,6 +307,7 @@ public:
GateRef IsSymbol(GateRef obj);
GateRef IsString(GateRef obj);
GateRef IsLineString(GateRef obj);
GateRef IsSlicedString(GateRef obj);
GateRef IsConstantString(GateRef obj);
GateRef IsTreeString(GateRef obj);
GateRef TreeStringIsFlat(GateRef string);
@ -639,12 +641,11 @@ public:
GateRef callField, GateRef method, Label* notFastBuiltins, Label* exit, Variable* result,
std::initializer_list<GateRef> args, JSCallMode mode);
inline void SetLength(GateRef glue, GateRef str, GateRef length, bool compressed);
inline void SetLength(GateRef glue, GateRef str, GateRef length, GateRef isCompressed);
inline void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode);
void Assert(int messageId, int line, GateRef glue, GateRef condition, Label *nextLabel);
GateRef FlattenString(GateRef glue, GateRef str);
void FlattenString(GateRef str, Variable *flatStr, Label *fastPath, Label *slowPath);
GateRef GetNormalStringData(GateRef str);
GateRef GetNormalStringData(const StringInfoGateRef &stringInfoGate);
void Comment(GateRef glue, const std::string &str);
GateRef ToNumber(GateRef glue, GateRef tagged);

View File

@ -322,26 +322,28 @@ void TypeMCRLowering::LowerFlattenStringCheck(GateRef gate, GateRef glue)
GateRef str = acc_.GetValueIn(gate, 0);
DEFVAlUE(result, (&builder_), VariableType::JS_POINTER(), str);
Label isTreeString(&builder_);
Label notTreeString(&builder_);
Label needFlat(&builder_);
Label exit(&builder_);
builder_.Branch(builder_.IsTreeString(str), &isTreeString, &exit);
builder_.Branch(builder_.IsTreeString(str), &isTreeString, &notTreeString);
builder_.Bind(&isTreeString);
{
Label isFlat(&builder_);
Label notFlat(&builder_);
builder_.Branch(builder_.TreeStringIsFlat(str), &isFlat, &notFlat);
builder_.Branch(builder_.TreeStringIsFlat(str), &isFlat, &needFlat);
builder_.Bind(&isFlat);
{
result = builder_.GetFirstFromTreeString(str);
builder_.Jump(&exit);
}
builder_.Bind(&notFlat);
{
result = LowerCallRuntime(glue, gate, RTSTUB_ID(SlowFlattenString), { str }, true);
builder_.Jump(&exit);
}
}
builder_.Bind(&notTreeString);
builder_.Branch(builder_.IsSlicedString(str), &needFlat, &exit);
builder_.Bind(&needFlat);
{
result = LowerCallRuntime(glue, gate, RTSTUB_ID(SlowFlattenString), { str }, true);
builder_.Jump(&exit);
}
builder_.Bind(&exit);
acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
}

View File

@ -260,6 +260,7 @@ CString *HeapSnapshot::GenerateNodeName(TaggedObject *entry)
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING:
case JSType::SLICED_STRING:
return GetString("BaseString");
case JSType::JS_OBJECT: {
CString objName = CString("JSOBJECT(Ctor="); // Ctor-name

View File

@ -151,6 +151,7 @@ CString JSHClass::DumpJSType(JSType type)
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING:
case JSType::SLICED_STRING:
return "BaseString";
case JSType::JS_NATIVE_POINTER:
return "NativePointer";
@ -658,6 +659,7 @@ static void DumpObject(TaggedObject *obj, std::ostream &os)
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING:
case JSType::SLICED_STRING:
DumpStringClass(EcmaString::Cast(obj), os);
os << "\n";
break;
@ -3737,6 +3739,7 @@ static void DumpObject(TaggedObject *obj, std::vector<Reference> &vec, bool isVm
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING:
case JSType::SLICED_STRING:
DumpStringClass(EcmaString::Cast(obj), vec);
return;
case JSType::JS_NATIVE_POINTER:

View File

@ -139,6 +139,13 @@ inline EcmaString *EcmaString::CreateLineStringWithSpaceType(const EcmaVM *vm, s
return string;
}
inline SlicedString *EcmaString::CreateSlicedString(const EcmaVM *vm, MemSpaceType type)
{
auto slicedString = SlicedString::Cast(vm->GetFactory()->AllocSlicedStringObject(type));
slicedString->SetRawHashcode(0);
return slicedString;
}
inline EcmaString *EcmaString::CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data,
size_t length, bool compressed, MemSpaceType type, uint32_t idOffset)
{
@ -168,36 +175,38 @@ inline EcmaString *EcmaString::CreateTreeString(const EcmaVM *vm,
EcmaString *EcmaString::FastSubUtf8String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
uint32_t length)
{
ASSERT(src->IsLineOrConstantString());
auto string = CreateLineString(vm, length, true);
JSHandle<EcmaString> string(vm->GetJSThread(), CreateLineString(vm, length, true));
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
FlatStringInfo srcFlat = FlattenAllString(vm, src);
Span<uint8_t> dst(string->GetDataUtf8Writable(), length);
Span<const uint8_t> source(src->GetDataUtf8() + start, length);
Span<const uint8_t> source(srcFlat.GetDataUtf8() + start, length);
EcmaString::MemCopyChars(dst, length, source, length);
ASSERT_PRINT(CanBeCompressed(string), "canBeCompresse does not match the real value!");
return string;
ASSERT_PRINT(CanBeCompressed(*string), "canBeCompresse does not match the real value!");
return *string;
}
/* static */
EcmaString *EcmaString::FastSubUtf16String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
uint32_t length)
{
ASSERT(src->IsLineOrConstantString());
bool canBeCompressed = CanBeCompressed(src->GetDataUtf16() + start, length);
auto string = CreateLineString(vm, length, canBeCompressed);
FlatStringInfo srcFlat = FlattenAllString(vm, src);
bool canBeCompressed = CanBeCompressed(srcFlat.GetDataUtf16() + start, length);
JSHandle<EcmaString> string(vm->GetJSThread(), CreateLineString(vm, length, canBeCompressed));
// maybe happen GC,so get srcFlat again
srcFlat = FlattenAllString(vm, src);
if (canBeCompressed) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
CopyChars(string->GetDataUtf8Writable(), src->GetDataUtf16() + start, length);
CopyChars(string->GetDataUtf8Writable(), srcFlat.GetDataUtf16() + start, length);
} else {
uint32_t len = length * (sizeof(uint16_t) / sizeof(uint8_t));
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Span<uint16_t> dst(string->GetDataUtf16Writable(), length);
Span<const uint16_t> source(src->GetDataUtf16() + start, length);
Span<const uint16_t> source(srcFlat.GetDataUtf16() + start, length);
EcmaString::MemCopyChars(dst, len, source, len);
}
ASSERT_PRINT(canBeCompressed == CanBeCompressed(string), "canBeCompresse does not match the real value!");
return string;
ASSERT_PRINT(canBeCompressed == CanBeCompressed(*string), "canBeCompresse does not match the real value!");
return *string;
}
inline uint16_t *EcmaString::GetData() const
@ -209,10 +218,10 @@ inline uint16_t *EcmaString::GetData() const
inline const uint8_t *EcmaString::GetDataUtf8() const
{
ASSERT_PRINT(IsUtf8(), "EcmaString: Read data as utf8 for utf16 string");
if (IsConstantString()) {
return ConstantString::Cast(this)->GetConstantData();
if (IsLineString()) {
return reinterpret_cast<uint8_t *>(GetData());
}
return reinterpret_cast<uint8_t *>(GetData());
return ConstantString::Cast(this)->GetConstantData();
}
inline const uint16_t *EcmaString::GetDataUtf16() const
@ -238,11 +247,12 @@ inline uint16_t *EcmaString::GetDataUtf16Writable()
inline size_t EcmaString::GetUtf8Length(bool modify) const
{
ASSERT(IsLineOrConstantString());
if (!IsUtf16()) {
return GetLength() + 1; // add place for zero in the end
}
return base::utf_helper::Utf16ToUtf8Size(GetData(), GetLength(), modify);
CVector<uint16_t> tmpBuf;
const uint16_t *data = GetUtf16DataFlat(this, tmpBuf);
return base::utf_helper::Utf16ToUtf8Size(data, GetLength(), modify);
}
template<bool verify>
@ -254,12 +264,18 @@ inline uint16_t EcmaString::At(int32_t index) const
return 0;
}
}
if (IsLineString()) {
return LineEcmaString::Cast(this)->Get<verify>(index);
} else if (IsConstantString()) {
return ConstantString::Cast(this)->Get<verify>(index);
} else {
return TreeEcmaString::Cast(this)->Get<verify>(index);
switch (GetStringType()) {
case JSType::LINE_STRING:
return LineEcmaString::Cast(this)->Get<verify>(index);
case JSType::CONSTANT_STRING:
return ConstantString::Cast(this)->Get<verify>(index);
case JSType::SLICED_STRING:
return SlicedString::Cast(this)->Get<verify>(index);
case JSType::TREE_STRING:
return TreeEcmaString::Cast(this)->Get<verify>(index);
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
}
@ -337,6 +353,15 @@ void EcmaString::WriteToFlat(EcmaString *src, Char *buf, uint32_t maxLength)
}
continue;
}
case JSType::SLICED_STRING: {
EcmaString *parent = EcmaString::Cast(SlicedString::Cast(src)->GetParent());
if (src->IsUtf8()) {
CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex(), length);
} else {
CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex(), length);
}
return;
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
@ -344,6 +369,21 @@ void EcmaString::WriteToFlat(EcmaString *src, Char *buf, uint32_t maxLength)
}
}
inline const uint8_t *FlatStringInfo::GetDataUtf8() const
{
return string_->GetDataUtf8() + startIndex_;
}
inline const uint16_t *FlatStringInfo::GetDataUtf16() const
{
return string_->GetDataUtf16() + startIndex_;
}
inline uint8_t *FlatStringInfo::GetDataUtf8Writable() const
{
return string_->GetDataUtf8Writable() + startIndex_;
}
inline const uint8_t *EcmaStringAccessor::GetDataUtf8()
{
return string_->GetDataUtf8();

View File

@ -97,32 +97,29 @@ EcmaString *EcmaString::Concat(const EcmaVM *vm,
EcmaString *EcmaString::CopyStringToOldSpace(const EcmaVM *vm, const JSHandle<EcmaString> &original,
uint32_t length, bool compressed)
{
EcmaString *strOrigin = *original;
ASSERT(strOrigin->IsLineOrConstantString());
EcmaString *newString = nullptr;
if (strOrigin->IsLineString()) {
newString = CreateLineStringWithSpaceType(vm, length, compressed, MemSpaceType::OLD_SPACE);
} else if (strOrigin->IsConstantString()) {
return CreateConstantString(vm, strOrigin->GetDataUtf8(), length, MemSpaceType::OLD_SPACE);
if (original->IsConstantString()) {
return CreateConstantString(vm, original->GetDataUtf8(), length, MemSpaceType::OLD_SPACE);
}
strOrigin = *original;
JSHandle<EcmaString> newString(vm->GetJSThread(),
CreateLineStringWithSpaceType(vm, length, compressed, MemSpaceType::OLD_SPACE));
auto strOrigin = FlattenAllString(vm, original);
if (compressed) {
// copy
Span<uint8_t> sp(newString->GetDataUtf8Writable(), length);
Span<const uint8_t> srcSp(strOrigin->GetDataUtf8(), length);
Span<const uint8_t> srcSp(strOrigin.GetDataUtf8(), length);
EcmaString::MemCopyChars(sp, length, srcSp, length);
} else {
// copy left part
Span<uint16_t> sp(newString->GetDataUtf16Writable(), length);
if (strOrigin->IsUtf8()) {
EcmaString::CopyChars(sp.data(), strOrigin->GetDataUtf8(), length);
if (strOrigin.IsUtf8()) {
EcmaString::CopyChars(sp.data(), strOrigin.GetDataUtf8(), length);
} else {
Span<const uint16_t> srcSp(strOrigin->GetDataUtf16(), length);
Span<const uint16_t> srcSp(strOrigin.GetDataUtf16(), length);
EcmaString::MemCopyChars(sp, length << 1U, srcSp, length << 1U);
}
}
ASSERT_PRINT(compressed == CanBeCompressed(newString), "compressed does not match the real value!");
return newString;
ASSERT_PRINT(compressed == CanBeCompressed(*newString), "compressed does not match the real value!");
return *newString;
}
/* static */
@ -136,11 +133,26 @@ EcmaString *EcmaString::FastSubString(const EcmaVM *vm,
if (start == 0 && length == src->GetLength()) {
return *src;
}
auto srcFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, src));
if (srcFlat->IsUtf8()) {
return FastSubUtf8String(vm, srcFlat, start, length);
if (src->IsUtf8()) {
return FastSubUtf8String(vm, src, start, length);
}
return FastSubUtf16String(vm, srcFlat, start, length);
return FastSubUtf16String(vm, src, start, length);
}
/* static */
EcmaString *EcmaString::GetSlicedString(const EcmaVM *vm,
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
{
ASSERT((start + length) <= src->GetLength());
if (start == 0 && length == src->GetLength()) {
return *src;
}
JSHandle<SlicedString> slicedString(vm->GetJSThread(), CreateSlicedString(vm));
FlatStringInfo srcFlat = FlattenAllString(vm, src);
slicedString->SetLength(length, srcFlat.GetString()->IsUtf8());
slicedString->SetParent(vm->GetJSThread(), JSTaggedValue(srcFlat.GetString()));
slicedString->SetStartIndex(start + srcFlat.GetStartIndex());
return *slicedString;
}
void EcmaString::WriteData(EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length)
@ -194,38 +206,38 @@ int32_t EcmaString::Compare(const EcmaVM *vm, const JSHandle<EcmaString> &left,
if (*left == *right) {
return 0;
}
auto leftFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, left));
auto rightFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, right));
EcmaString *lhs = *leftFlat;
EcmaString *rhs = *rightFlat;
int32_t lhsCount = static_cast<int32_t>(lhs->GetLength());
int32_t rhsCount = static_cast<int32_t>(rhs->GetLength());
FlatStringInfo lhs = FlattenAllString(vm, left);
JSHandle<EcmaString> string(vm->GetJSThread(), lhs.GetString());
FlatStringInfo rhs = FlattenAllString(vm, right);
lhs.SetString(*string);
int32_t lhsCount = static_cast<int32_t>(lhs.GetLength());
int32_t rhsCount = static_cast<int32_t>(rhs.GetLength());
int32_t countDiff = lhsCount - rhsCount;
int32_t minCount = (countDiff < 0) ? lhsCount : rhsCount;
if (!lhs->IsUtf16() && !rhs->IsUtf16()) {
Span<const uint8_t> lhsSp(lhs->GetDataUtf8(), lhsCount);
Span<const uint8_t> rhsSp(rhs->GetDataUtf8(), rhsCount);
if (!lhs.IsUtf16() && !rhs.IsUtf16()) {
Span<const uint8_t> lhsSp(lhs.GetDataUtf8(), lhsCount);
Span<const uint8_t> rhsSp(rhs.GetDataUtf8(), rhsCount);
int32_t charDiff = CompareStringSpan(lhsSp, rhsSp, minCount);
if (charDiff != 0) {
return charDiff;
}
} else if (!lhs->IsUtf16()) {
Span<const uint8_t> lhsSp(lhs->GetDataUtf8(), lhsCount);
Span<const uint16_t> rhsSp(rhs->GetDataUtf16(), rhsCount);
} else if (!lhs.IsUtf16()) {
Span<const uint8_t> lhsSp(lhs.GetDataUtf8(), lhsCount);
Span<const uint16_t> rhsSp(rhs.GetDataUtf16(), rhsCount);
int32_t charDiff = CompareStringSpan(lhsSp, rhsSp, minCount);
if (charDiff != 0) {
return charDiff;
}
} else if (!rhs->IsUtf16()) {
Span<const uint16_t> lhsSp(lhs->GetDataUtf16(), rhsCount);
Span<const uint8_t> rhsSp(rhs->GetDataUtf8(), lhsCount);
} else if (!rhs.IsUtf16()) {
Span<const uint16_t> lhsSp(lhs.GetDataUtf16(), rhsCount);
Span<const uint8_t> rhsSp(rhs.GetDataUtf8(), lhsCount);
int32_t charDiff = CompareStringSpan(lhsSp, rhsSp, minCount);
if (charDiff != 0) {
return charDiff;
}
} else {
Span<const uint16_t> lhsSp(lhs->GetDataUtf16(), lhsCount);
Span<const uint16_t> rhsSp(rhs->GetDataUtf16(), rhsCount);
Span<const uint16_t> lhsSp(lhs.GetDataUtf16(), lhsCount);
Span<const uint16_t> rhsSp(rhs.GetDataUtf16(), rhsCount);
int32_t charDiff = CompareStringSpan(lhsSp, rhsSp, minCount);
if (charDiff != 0) {
return charDiff;
@ -291,13 +303,13 @@ int32_t EcmaString::LastIndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, in
int32_t EcmaString::IndexOf(const EcmaVM *vm,
const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos)
{
EcmaString *lhs = *receiver;
EcmaString *rhs = *search;
if (lhs == nullptr || rhs == nullptr) {
EcmaString *lhstring = *receiver;
EcmaString *rhstring = *search;
if (lhstring == nullptr || rhstring == nullptr) {
return -1;
}
int32_t lhsCount = static_cast<int32_t>(lhs->GetLength());
int32_t rhsCount = static_cast<int32_t>(rhs->GetLength());
int32_t lhsCount = static_cast<int32_t>(lhstring->GetLength());
int32_t rhsCount = static_cast<int32_t>(rhstring->GetLength());
if (pos > lhsCount) {
return -1;
@ -320,24 +332,24 @@ int32_t EcmaString::IndexOf(const EcmaVM *vm,
return -1;
}
auto receiverFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, receiver));
auto searchFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, search));
lhs = *receiverFlat;
rhs = *searchFlat;
FlatStringInfo lhs = FlattenAllString(vm, receiver);
JSHandle<EcmaString> string(vm->GetJSThread(), lhs.GetString());
FlatStringInfo rhs = FlattenAllString(vm, search);
lhs.SetString(*string);
if (rhs->IsUtf8() && lhs->IsUtf8()) {
Span<const uint8_t> lhsSp(lhs->GetDataUtf8(), lhsCount);
Span<const uint8_t> rhsSp(rhs->GetDataUtf8(), rhsCount);
if (rhs.IsUtf8() && lhs.IsUtf8()) {
Span<const uint8_t> lhsSp(lhs.GetDataUtf8(), lhsCount);
Span<const uint8_t> rhsSp(rhs.GetDataUtf8(), rhsCount);
return EcmaString::IndexOf(lhsSp, rhsSp, pos, max);
} else if (rhs->IsUtf16() && lhs->IsUtf16()) { // NOLINT(readability-else-after-return)
Span<const uint16_t> lhsSp(lhs->GetDataUtf16(), lhsCount);
Span<const uint16_t> rhsSp(rhs->GetDataUtf16(), rhsCount);
} else if (rhs.IsUtf16() && lhs.IsUtf16()) { // NOLINT(readability-else-after-return)
Span<const uint16_t> lhsSp(lhs.GetDataUtf16(), lhsCount);
Span<const uint16_t> rhsSp(rhs.GetDataUtf16(), rhsCount);
return EcmaString::IndexOf(lhsSp, rhsSp, pos, max);
} else if (rhs->IsUtf16()) {
} else if (rhs.IsUtf16()) {
return -1;
} else { // NOLINT(readability-else-after-return)
Span<const uint16_t> lhsSp(lhs->GetDataUtf16(), lhsCount);
Span<const uint8_t> rhsSp(rhs->GetDataUtf8(), rhsCount);
Span<const uint16_t> lhsSp(lhs.GetDataUtf16(), lhsCount);
Span<const uint8_t> rhsSp(rhs.GetDataUtf8(), rhsCount);
return EcmaString::IndexOf(lhsSp, rhsSp, pos, max);
}
}
@ -345,14 +357,14 @@ int32_t EcmaString::IndexOf(const EcmaVM *vm,
int32_t EcmaString::LastIndexOf(const EcmaVM *vm,
const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos)
{
EcmaString *lhs = *receiver;
EcmaString *rhs = *search;
if (lhs == nullptr || rhs == nullptr) {
EcmaString *lhstring = *receiver;
EcmaString *rhstring = *search;
if (lhstring == nullptr || rhstring == nullptr) {
return -1;
}
int32_t lhsCount = static_cast<int32_t>(lhs->GetLength());
int32_t rhsCount = static_cast<int32_t>(rhs->GetLength());
int32_t lhsCount = static_cast<int32_t>(lhstring->GetLength());
int32_t rhsCount = static_cast<int32_t>(rhstring->GetLength());
if (lhsCount < rhsCount) {
return -1;
}
@ -373,24 +385,21 @@ int32_t EcmaString::LastIndexOf(const EcmaVM *vm,
return pos;
}
auto receiverFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, receiver));
auto searchFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, search));
lhs = *receiverFlat;
rhs = *searchFlat;
if (rhs->IsUtf8() && lhs->IsUtf8()) {
Span<const uint8_t> lhsSp(lhs->GetDataUtf8(), lhsCount);
Span<const uint8_t> rhsSp(rhs->GetDataUtf8(), rhsCount);
FlatStringInfo lhs = FlattenAllString(vm, receiver);
FlatStringInfo rhs = FlattenAllString(vm, search);
if (rhs.IsUtf8() && lhs.IsUtf8()) {
Span<const uint8_t> lhsSp(lhs.GetDataUtf8(), lhsCount);
Span<const uint8_t> rhsSp(rhs.GetDataUtf8(), rhsCount);
return EcmaString::LastIndexOf(lhsSp, rhsSp, pos);
} else if (rhs->IsUtf16() && lhs->IsUtf16()) { // NOLINT(readability-else-after-return)
Span<const uint16_t> lhsSp(lhs->GetDataUtf16(), lhsCount);
Span<const uint16_t> rhsSp(rhs->GetDataUtf16(), rhsCount);
} else if (rhs.IsUtf16() && lhs.IsUtf16()) { // NOLINT(readability-else-after-return)
Span<const uint16_t> lhsSp(lhs.GetDataUtf16(), lhsCount);
Span<const uint16_t> rhsSp(rhs.GetDataUtf16(), rhsCount);
return EcmaString::LastIndexOf(lhsSp, rhsSp, pos);
} else if (rhs->IsUtf16()) {
} else if (rhs.IsUtf16()) {
return -1;
} else { // NOLINT(readability-else-after-return)
Span<const uint16_t> lhsSp(lhs->GetDataUtf16(), lhsCount);
Span<const uint8_t> rhsSp(rhs->GetDataUtf8(), rhsCount);
Span<const uint16_t> lhsSp(lhs.GetDataUtf16(), lhsCount);
Span<const uint8_t> rhsSp(rhs.GetDataUtf8(), rhsCount);
return EcmaString::LastIndexOf(lhsSp, rhsSp, pos);
}
}
@ -454,8 +463,8 @@ bool EcmaString::CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len)
bool EcmaString::EqualToSplicedString(const EcmaString *str1, const EcmaString *str2)
{
ASSERT(IsLineOrConstantString());
ASSERT(str1->IsLineOrConstantString() && str2->IsLineOrConstantString());
ASSERT(NotTreeString());
ASSERT(str1->NotTreeString() && str2->NotTreeString());
if (GetLength() != str1->GetLength() + str2->GetLength()) {
return false;
}
@ -463,18 +472,26 @@ bool EcmaString::EqualToSplicedString(const EcmaString *str1, const EcmaString *
if (str1->IsUtf8() && str2->IsUtf8()) {
return false;
}
if (EcmaString::StringsAreEqualUtf16(str1, GetDataUtf16(), str1->GetLength())) {
return EcmaString::StringsAreEqualUtf16(str2, GetDataUtf16() + str1->GetLength(), str2->GetLength());
CVector<uint16_t> buf;
const uint16_t *data = EcmaString::GetUtf16DataFlat(this, buf);
if (EcmaString::StringsAreEqualUtf16(str1, data, str1->GetLength())) {
return EcmaString::StringsAreEqualUtf16(str2, data + str1->GetLength(), str2->GetLength());
}
} else {
if (str1->IsUtf16() || str2->IsUtf16()) {
return false;
}
Span<const uint8_t> concatData(GetDataUtf8(), str1->GetLength());
Span<const uint8_t> data1(str1->GetDataUtf8(), str1->GetLength());
CVector<uint8_t> buf;
const uint8_t *data = EcmaString::GetUtf8DataFlat(this, buf);
CVector<uint8_t> bufStr1;
const uint8_t *dataStr1 = EcmaString::GetUtf8DataFlat(str1, bufStr1);
Span<const uint8_t> concatData(data, str1->GetLength());
Span<const uint8_t> data1(dataStr1, str1->GetLength());
if (EcmaString::StringsAreEquals(concatData, data1)) {
concatData = Span<const uint8_t>(GetDataUtf8() + str1->GetLength(), str2->GetLength());
Span<const uint8_t> data2(str2->GetDataUtf8(), str2->GetLength());
concatData = Span<const uint8_t>(data + str1->GetLength(), str2->GetLength());
CVector<uint8_t> bufStr2;
const uint8_t *dataStr2 = EcmaString::GetUtf8DataFlat(str2, bufStr2);
Span<const uint8_t> data2(dataStr2, str2->GetLength());
return EcmaString::StringsAreEquals(concatData, data2);
}
}
@ -503,6 +520,20 @@ bool EcmaString::StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *st
}
}
/* static */
bool EcmaString::StringsAreEqualSameUtfEncoding(const FlatStringInfo &str1, const FlatStringInfo &str2)
{
if (str1.IsUtf16()) {
Span<const uint16_t> sp1(str1.GetDataUtf16(), str1.GetLength());
Span<const uint16_t> sp2(str2.GetDataUtf16(), str2.GetLength());
return EcmaString::StringsAreEquals(sp1, sp2);
} else { // NOLINT(readability-else-after-return)
Span<const uint8_t> sp1(str1.GetDataUtf8(), str1.GetLength());
Span<const uint8_t> sp2(str2.GetDataUtf8(), str2.GetLength());
return EcmaString::StringsAreEquals(sp1, sp2);
}
}
bool EcmaString::StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &str1, const JSHandle<EcmaString> &str2)
{
if (str1 == str2) {
@ -526,10 +557,11 @@ bool EcmaString::StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &s
return false;
}
}
auto str1Flat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, str1));
auto str2Flat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, str2));
return StringsAreEqualSameUtfEncoding(*str1Flat, *str2Flat);
FlatStringInfo str1Flat = FlattenAllString(vm, str1);
JSHandle<EcmaString> string(vm->GetJSThread(), str1Flat.GetString());
FlatStringInfo str2Flat = FlattenAllString(vm, str2);
str1Flat.SetString(*string);
return StringsAreEqualSameUtfEncoding(str1Flat, str2Flat);
}
/* static */
@ -780,27 +812,27 @@ EcmaString *EcmaString::TrimBody(const JSThread *thread, const JSHandle<EcmaStri
/* static */
EcmaString *EcmaString::ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src)
{
auto srcFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, src));
uint32_t srcLength = srcFlat->GetLength();
auto srcFlat = FlattenAllString(vm, src);
uint32_t srcLength = srcFlat.GetLength();
auto factory = vm->GetFactory();
if (srcFlat->IsUtf16()) {
std::u16string u16str = base::StringHelper::Utf16ToU16String(srcFlat->GetDataUtf16(), srcLength);
if (srcFlat.IsUtf16()) {
std::u16string u16str = base::StringHelper::Utf16ToU16String(srcFlat.GetDataUtf16(), srcLength);
std::string res = base::StringHelper::ToLower(u16str);
return *(factory->NewFromStdString(res));
} else {
return ConvertUtf8ToLowerOrUpper(vm, srcFlat, true);
return ConvertUtf8ToLowerOrUpper(vm, src, true);
}
}
/* static */
EcmaString *EcmaString::TryToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src)
{
auto srcFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, src));
uint32_t srcLength = srcFlat->GetLength();
auto srcFlat = FlattenAllString(vm, src);
uint32_t srcLength = srcFlat.GetLength();
const char start = 'A';
const char end = 'Z';
uint32_t upperIndex = srcLength;
Span<uint8_t> data(srcFlat->GetDataUtf8Writable(), srcLength);
Span<uint8_t> data(srcFlat.GetDataUtf8Writable(), srcLength);
for (uint32_t index = 0; index < srcLength; ++index) {
if (base::StringHelper::Utf8CharInRange(data[index], start, end)) {
upperIndex = index;
@ -810,18 +842,19 @@ EcmaString *EcmaString::TryToLower(const EcmaVM *vm, const JSHandle<EcmaString>
if (upperIndex == srcLength) {
return *src;
}
return ConvertUtf8ToLowerOrUpper(vm, srcFlat, true, upperIndex);
return ConvertUtf8ToLowerOrUpper(vm, src, true, upperIndex);
}
/* static */
EcmaString *EcmaString::ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHandle<EcmaString> &srcFlat,
EcmaString *EcmaString::ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src,
bool toLower, uint32_t startIndex)
{
const char start = toLower ? 'A' : 'a';
const char end = toLower ? 'Z' : 'z';
uint32_t srcLength = srcFlat->GetLength();
auto newString = CreateLineString(vm, srcLength, true);
Span<uint8_t> data(srcFlat->GetDataUtf8Writable(), srcLength);
uint32_t srcLength = src->GetLength();
JSHandle<EcmaString> newString(vm->GetJSThread(), CreateLineString(vm, srcLength, true));
auto srcFlat = FlattenAllString(vm, src);
Span<uint8_t> data(srcFlat.GetDataUtf8Writable(), srcLength);
auto newStringPtr = newString->GetDataUtf8Writable();
if (startIndex > 0) {
if (memcpy_s(newStringPtr, startIndex * sizeof(uint8_t), data.data(), startIndex * sizeof(uint8_t)) != EOK) {
@ -836,21 +869,21 @@ EcmaString *EcmaString::ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHand
*(newStringPtr + index) = data[index];
}
}
return newString;
return *newString;
}
/* static */
EcmaString *EcmaString::ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src)
{
auto srcFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, src));
uint32_t srcLength = srcFlat->GetLength();
FlatStringInfo srcFlat = FlattenAllString(vm, src);
uint32_t srcLength = srcFlat.GetLength();
auto factory = vm->GetFactory();
if (srcFlat->IsUtf16()) {
std::u16string u16str = base::StringHelper::Utf16ToU16String(srcFlat->GetDataUtf16(), srcLength);
if (srcFlat.IsUtf16()) {
std::u16string u16str = base::StringHelper::Utf16ToU16String(srcFlat.GetDataUtf16(), srcLength);
std::string res = base::StringHelper::ToUpper(u16str);
return *(factory->NewFromStdString(res));
} else {
return ConvertUtf8ToLowerOrUpper(vm, srcFlat, false);
return ConvertUtf8ToLowerOrUpper(vm, src, false);
}
}
@ -858,8 +891,8 @@ EcmaString *EcmaString::ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &sr
EcmaString *EcmaString::ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale)
{
auto factory = vm->GetFactory();
auto srcFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, src));
std::u16string utf16 = srcFlat->ToU16String();
FlatStringInfo srcFlat = FlattenAllString(vm, src);
std::u16string utf16 = srcFlat.ToU16String();
std::string res = base::StringHelper::ToLocaleLower(utf16, locale);
return *(factory->NewFromStdString(res));
}
@ -868,33 +901,32 @@ EcmaString *EcmaString::ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaStrin
EcmaString *EcmaString::ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale)
{
auto factory = vm->GetFactory();
auto srcFlat = JSHandle<EcmaString>(vm->GetJSThread(), Flatten(vm, src));
std::u16string utf16 = srcFlat->ToU16String();
FlatStringInfo srcFlat = FlattenAllString(vm, src);
std::u16string utf16 = srcFlat.ToU16String();
std::string res = base::StringHelper::ToLocaleUpper(utf16, locale);
return *(factory->NewFromStdString(res));
}
EcmaString *EcmaString::Trim(const JSThread *thread, const JSHandle<EcmaString> &src, TrimMode mode)
{
auto srcFlat = JSHandle<EcmaString>(thread, Flatten(thread->GetEcmaVM(), src));
uint32_t srcLen = srcFlat->GetLength();
FlatStringInfo srcFlat = FlattenAllString(thread->GetEcmaVM(), src);
uint32_t srcLen = srcFlat.GetLength();
if (UNLIKELY(srcLen == 0)) {
return EcmaString::Cast(thread->GlobalConstants()->GetEmptyString().GetTaggedObject());
}
if (srcFlat->IsUtf8()) {
Span<const uint8_t> data(srcFlat->GetDataUtf8(), srcLen);
return TrimBody(thread, srcFlat, data, mode);
if (srcFlat.IsUtf8()) {
Span<const uint8_t> data(srcFlat.GetDataUtf8(), srcLen);
return TrimBody(thread, src, data, mode);
} else {
Span<const uint16_t> data(srcFlat->GetDataUtf16(), srcLen);
return TrimBody(thread, srcFlat, data, mode);
Span<const uint16_t> data(srcFlat.GetDataUtf16(), srcLen);
return TrimBody(thread, src, data, mode);
}
}
EcmaString *EcmaString::SlowFlatten(const EcmaVM *vm, const JSHandle<TreeEcmaString> &string, MemSpaceType type)
EcmaString *EcmaString::SlowFlatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, MemSpaceType type)
{
ASSERT(string->IsTreeString() || string->IsSlicedString());
auto thread = vm->GetJSThread();
ASSERT(EcmaString::Cast(string->GetSecond())->GetLength() != 0);
uint32_t length = string->GetLength();
EcmaString *result = nullptr;
if (string->IsUtf8()) {
@ -904,27 +936,52 @@ EcmaString *EcmaString::SlowFlatten(const EcmaVM *vm, const JSHandle<TreeEcmaStr
result = CreateLineStringWithSpaceType(vm, length, false, type);
WriteToFlat<uint16_t>(*string, result->GetDataUtf16Writable(), length);
}
string->SetFirst(thread, JSTaggedValue(result));
string->SetSecond(thread, JSTaggedValue(*vm->GetFactory()->GetEmptyString()));
if (string->IsTreeString()) {
JSHandle<TreeEcmaString> tree(string);
ASSERT(EcmaString::Cast(tree->GetSecond())->GetLength() != 0);
tree->SetFirst(thread, JSTaggedValue(result));
tree->SetSecond(thread, JSTaggedValue(*vm->GetFactory()->GetEmptyString()));
}
return result;
}
EcmaString *EcmaString::Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, MemSpaceType type)
{
EcmaString *s = *string;
if (s->IsLineOrConstantString()) {
if (s->IsLineOrConstantString() || s->IsSlicedString()) {
return s;
}
if (s->IsTreeString()) {
JSHandle<TreeEcmaString> tree = JSHandle<TreeEcmaString>::Cast(string);
if (!tree->IsFlat()) {
return SlowFlatten(vm, tree, type);
return SlowFlatten(vm, string, type);
}
s = EcmaString::Cast(tree->GetFirst());
}
return s;
}
FlatStringInfo EcmaString::FlattenAllString(const EcmaVM *vm, const JSHandle<EcmaString> &string, MemSpaceType type)
{
EcmaString *s = *string;
uint32_t startIndex = 0;
if (s->IsLineOrConstantString()) {
return FlatStringInfo(s, startIndex, s->GetLength());
}
if (string->IsTreeString()) {
JSHandle<TreeEcmaString> tree = JSHandle<TreeEcmaString>::Cast(string);
if (!tree->IsFlat()) {
s = SlowFlatten(vm, string, type);
} else {
s = EcmaString::Cast(tree->GetFirst());
}
} else if (string->IsSlicedString()) {
s = EcmaString::Cast(SlicedString::Cast(*string)->GetParent());
startIndex = SlicedString::Cast(*string)->GetStartIndex();
}
return FlatStringInfo(s, startIndex, s->GetLength());
}
EcmaString *EcmaString::FlattenNoGC(const EcmaVM *vm, EcmaString *string)
{
DISALLOW_GARBAGE_COLLECTION;
@ -949,6 +1006,18 @@ EcmaString *EcmaString::FlattenNoGC(const EcmaVM *vm, EcmaString *string)
tree->SetSecond(vm->GetJSThread(), JSTaggedValue(*vm->GetFactory()->GetEmptyString()));
return result;
}
} else if (string->IsSlicedString()) {
SlicedString *str = SlicedString::Cast(string);
uint32_t length = str->GetLength();
EcmaString *result = nullptr;
if (str->IsUtf8()) {
result = CreateLineStringNoGC(vm, length, true);
WriteToFlat<uint8_t>(str, result->GetDataUtf8Writable(), length);
} else {
result = CreateLineStringNoGC(vm, length, false);
WriteToFlat<uint16_t>(str, result->GetDataUtf16Writable(), length);
}
return result;
}
return string;
}
@ -966,6 +1035,9 @@ const uint8_t *EcmaString::GetUtf8DataFlat(const EcmaString *src, CVector<uint8_
WriteToFlat(string, buf.data(), length);
return buf.data();
}
} else if (string->IsSlicedString()) {
SlicedString *str = SlicedString::Cast(string);
return EcmaString::Cast(str->GetParent())->GetDataUtf8() + str->GetStartIndex();
}
return string->GetDataUtf8();
}
@ -983,10 +1055,27 @@ const uint16_t *EcmaString::GetUtf16DataFlat(const EcmaString *src, CVector<uint
WriteToFlat(string, buf.data(), length);
return buf.data();
}
} else if (string->IsSlicedString()) {
SlicedString *str = SlicedString::Cast(string);
return EcmaString::Cast(str->GetParent())->GetDataUtf16() + str->GetStartIndex();
}
return string->GetDataUtf16();
}
std::u16string FlatStringInfo::ToU16String(uint32_t len)
{
uint32_t length = len > 0 ? len : GetLength();
std::u16string result;
if (IsUtf16()) {
const uint16_t *data = this->GetDataUtf16();
result = base::StringHelper::Utf16ToU16String(data, length);
} else {
const uint8_t *data = this->GetDataUtf8();
result = base::StringHelper::Utf8ToU16String(data, length);
}
return result;
}
EcmaStringAccessor::EcmaStringAccessor(EcmaString *string)
{
ASSERT(string != nullptr);

View File

@ -42,6 +42,8 @@ class EcmaVM;
class LineEcmaString;
class ConstantString;
class TreeEcmaString;
class SlicedString;
class FlatStringInfo;
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define ECMA_STRING_CHECK_LENGTH_AND_TRHOW(vm, length) \
@ -78,6 +80,8 @@ private:
friend class LineEcmaString;
friend class ConstantString;
friend class TreeEcmaString;
friend class SlicedString;
friend class FlatStringInfo;
friend class NameDictionary;
static constexpr int SMALL_STRING_SIZE = 128;
@ -88,6 +92,7 @@ private:
uint32_t idOffset = 0);
static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE);
static SlicedString *CreateSlicedString(const EcmaVM *vm, MemSpaceType type = MemSpaceType::SEMI_SPACE);
static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed);
static EcmaString *CreateLineStringNoGC(const EcmaVM *vm, size_t length, bool compressed);
static EcmaString *CreateLineStringWithSpaceType(const EcmaVM *vm,
@ -102,6 +107,8 @@ private:
uint32_t length, bool compressed);
static EcmaString *FastSubString(const EcmaVM *vm,
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
static EcmaString *GetSlicedString(const EcmaVM *vm,
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
// require src is LineString
// not change src data structure
static inline EcmaString *FastSubUtf8String(const EcmaVM *vm,
@ -227,6 +234,7 @@ private:
static bool StringsAreEqual(EcmaString *str1, EcmaString *str2);
// Two strings have the same type of utf encoding format.
static bool StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *str2);
static bool StringsAreEqualSameUtfEncoding(const FlatStringInfo &str1, const FlatStringInfo &str2);
// Compares strings by bytes, It doesn't check canonical unicode equivalence.
// not change str1 data structure.
// if str1 is not flat, this func has low efficiency.
@ -509,10 +517,18 @@ private:
{
return GetClass()->IsConstantString();
}
bool IsSlicedString() const
{
return GetClass()->IsSlicedString();
}
bool IsTreeString() const
{
return GetClass()->IsTreeString();
}
bool NotTreeString() const
{
return !IsTreeString();
}
bool IsLineOrConstantString() const
{
auto hclass = GetClass();
@ -534,11 +550,14 @@ private:
static const uint16_t *GetUtf16DataFlat(const EcmaString *src, CVector<uint16_t> &buf);
// string must be not flat
static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<TreeEcmaString> &string, MemSpaceType type);
static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, MemSpaceType type);
static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
MemSpaceType type = MemSpaceType::SEMI_SPACE);
static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle<EcmaString> &string,
MemSpaceType type = MemSpaceType::SEMI_SPACE);
static EcmaString *FlattenNoGC(const EcmaVM *vm, EcmaString *string);
static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src);
@ -666,6 +685,57 @@ public:
}
};
// The substrings of another string use SlicedString to describe.
class SlicedString : public EcmaString {
public:
static constexpr uint32_t MIN_SLICED_ECMASTRING_LENGTH = 13;
static constexpr size_t PARENT_OFFSET = EcmaString::SIZE;
ACCESSORS(Parent, PARENT_OFFSET, STARTINDEX_OFFSET);
ACCESSORS_PRIMITIVE_FIELD(StartIndex, uint32_t, STARTINDEX_OFFSET, SIZE);
DECL_VISIT_OBJECT(PARENT_OFFSET, STARTINDEX_OFFSET);
CAST_CHECK(SlicedString, IsSlicedString);
private:
friend class EcmaString;
static SlicedString *Cast(EcmaString *str)
{
return static_cast<SlicedString *>(str);
}
static SlicedString *Cast(const EcmaString *str)
{
return SlicedString::Cast(const_cast<EcmaString *>(str));
}
static size_t ObjectSize()
{
return SlicedString::SIZE;
}
// Minimum length for a sliced string
template<bool verify = true>
uint16_t Get(int32_t index) const
{
int32_t length = static_cast<int32_t>(GetLength());
if (verify) {
if ((index < 0) || (index >= length)) {
return 0;
}
}
EcmaString *parent = EcmaString::Cast(GetParent());
if (parent->IsLineString()) {
if (parent->IsUtf8()) {
Span<const uint8_t> sp(parent->GetDataUtf8() + GetStartIndex(), length);
return sp[index];
}
Span<const uint16_t> sp(parent->GetDataUtf16() + GetStartIndex(), length);
return sp[index];
}
Span<const uint8_t> sp(ConstantString::Cast(parent)->GetConstantData() + GetStartIndex(), length);
return sp[index];
}
};
class TreeEcmaString : public EcmaString {
public:
// Minimum length for a tree string
@ -727,6 +797,51 @@ public:
}
};
class FlatStringInfo {
public:
FlatStringInfo(EcmaString *string, uint32_t startIndex, uint32_t length) : string_(string),
startIndex_(startIndex),
length_(length) {}
bool IsUtf8() const
{
return string_->IsUtf8();
}
bool IsUtf16() const
{
return string_->IsUtf16();
}
EcmaString *GetString() const
{
return string_;
}
void SetString(EcmaString *string)
{
string_ = string;
}
uint32_t GetStartIndex() const
{
return startIndex_;
}
uint32_t GetLength() const
{
return length_;
}
const uint8_t *GetDataUtf8() const;
const uint16_t *GetDataUtf16() const;
uint8_t *GetDataUtf8Writable() const;
std::u16string ToU16String(uint32_t len = 0);
private:
EcmaString *string_ {nullptr};
uint32_t startIndex_ {0};
uint32_t length_ {0};
};
// if you want to use functions of EcmaString, please not use directly,
// and use functions of EcmaStringAccessor alternatively.
// eg: EcmaString *str = ***; str->GetLength() -----> EcmaStringAccessor(str).GetLength()
@ -788,6 +903,13 @@ public:
return EcmaString::FastSubString(vm, src, start, length);
}
// get
static EcmaString *GetSlicedString(const EcmaVM *vm,
const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
{
return EcmaString::GetSlicedString(vm, src, start, length);
}
bool IsUtf8() const
{
return string_->IsUtf8();
@ -1093,13 +1215,24 @@ public:
return string_->IsTreeString();
}
bool NotTreeString() const
{
return string_->NotTreeString();
}
static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
MemSpaceType type = MemSpaceType::SEMI_SPACE)
{
return EcmaString::Flatten(vm, string, type);
}
static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<TreeEcmaString> &string,
static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle<EcmaString> &string,
MemSpaceType type = MemSpaceType::SEMI_SPACE)
{
return EcmaString::FlattenAllString(vm, string, type);
}
static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
MemSpaceType type = MemSpaceType::SEMI_SPACE)
{
return EcmaString::SlowFlatten(vm, string, type);

View File

@ -27,8 +27,8 @@ EcmaStringTable::EcmaStringTable(const EcmaVM *vm) : vm_(vm) {}
EcmaString *EcmaStringTable::GetString(const JSHandle<EcmaString> &firstString,
const JSHandle<EcmaString> &secondString) const
{
ASSERT(EcmaStringAccessor(firstString).IsLineOrConstantString());
ASSERT(EcmaStringAccessor(secondString).IsLineOrConstantString());
ASSERT(EcmaStringAccessor(firstString).NotTreeString());
ASSERT(EcmaStringAccessor(secondString).NotTreeString());
uint32_t hashCode = EcmaStringAccessor(firstString).GetHashcode();
hashCode = EcmaStringAccessor(secondString).ComputeHashcode(hashCode);
auto range = table_.equal_range(hashCode);
@ -69,7 +69,7 @@ EcmaString *EcmaStringTable::GetString(const uint16_t *utf16Data, uint32_t utf16
EcmaString *EcmaStringTable::GetString(EcmaString *string) const
{
ASSERT(EcmaStringAccessor(string).IsLineOrConstantString());
ASSERT(EcmaStringAccessor(string).NotTreeString());
auto hashcode = EcmaStringAccessor(string).GetHashcode();
auto range = table_.equal_range(hashcode);
for (auto item = range.first; item != range.second; ++item) {
@ -88,7 +88,7 @@ void EcmaStringTable::InternString(EcmaString *string)
}
// Strings in string table should not be in the young space.
ASSERT(!Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(string))->InYoungSpace());
ASSERT(EcmaStringAccessor(string).IsLineOrConstantString());
ASSERT(EcmaStringAccessor(string).NotTreeString());
auto hashcode = EcmaStringAccessor(string).GetHashcode();
table_.emplace(hashcode, string);
EcmaStringAccessor(string).SetInternString();
@ -171,7 +171,7 @@ EcmaString *EcmaStringTable::GetOrInternString(EcmaString *string)
return result;
}
if (EcmaStringAccessor(strFlat).IsLineOrConstantString()) {
if (EcmaStringAccessor(strFlat).NotTreeString()) {
Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(strFlat));
if (objectRegion->InYoungSpace()) {
JSHandle<EcmaString> resultHandle(vm_->GetJSThread(), strFlat);
@ -240,7 +240,7 @@ bool EcmaStringTable::CheckStringTableValidity()
{
for (auto itemOuter = table_.begin(); itemOuter != table_.end(); ++itemOuter) {
auto outerString = itemOuter->second;
if (!EcmaStringAccessor(outerString).IsLineOrConstantString()) {
if (!EcmaStringAccessor(outerString).NotTreeString()) {
return false;
}
int counter = 0;

View File

@ -95,6 +95,8 @@ void GlobalEnvConstants::InitRootsClass(JSThread *thread, JSHClass *hClass)
SetConstant(ConstantIndex::FREE_OBJECT_WITH_TWO_FIELD_CLASS_INDEX,
factory->NewEcmaReadOnlyHClass(hClass, FreeObject::SIZE, JSType::FREE_OBJECT_WITH_TWO_FIELD));
SetConstant(ConstantIndex::LINE_STRING_CLASS_INDEX, factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::LINE_STRING));
SetConstant(ConstantIndex::SLICED_STRING_CLASS_INDEX,
factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::SLICED_STRING));
SetConstant(ConstantIndex::CONSTANT_STRING_CLASS_INDEX,
factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::CONSTANT_STRING));
SetConstant(ConstantIndex::TREE_STRING_CLASS_INDEX, factory->NewEcmaReadOnlyHClass(hClass, 0, JSType::TREE_STRING));

View File

@ -37,6 +37,7 @@ class ObjectFactory;
V(JSTaggedValue, FreeObjectWithOneFieldClass, FREE_OBJECT_WITH_ONE_FIELD_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, FreeObjectWithTwoFieldClass, FREE_OBJECT_WITH_TWO_FIELD_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, LineStringClass, LINE_STRING_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, SlicedStringClass, SLICED_STRING_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ConstantStringClass, CONSTANT_STRING_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, TreeStringClass, TREE_STRING_CLASS_INDEX, ecma_roots_class) \
V(JSTaggedValue, ArrayClass, ARRAY_CLASS_INDEX, ecma_roots_class) \

View File

@ -206,6 +206,10 @@ inline size_t JSHClass::SizeFromJSHClass(TaggedObject *header)
size = TreeEcmaString::SIZE;
size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
break;
case JSType::SLICED_STRING:
size = SlicedString::SIZE;
size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
break;
case JSType::MACHINE_CODE_OBJECT:
size = reinterpret_cast<MachineCode *>(header)->GetMachineCodeObjectSize();
size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));

View File

@ -188,6 +188,7 @@ struct Reference;
HCLASS, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \
LINE_STRING, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */\
CONSTANT_STRING, /* ///////////////////////////////////////////////////////////////////////////////-PADDING */\
SLICED_STRING, /* ////////////////////////////////////////////////////////////////////////////////-PADDING */ \
TREE_STRING, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \
BIGINT, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \
TAGGED_ARRAY, /* //////////////////////////////////////////////////////////////////////////////////-PADDING */ \
@ -526,6 +527,11 @@ public:
return GetObjectType() == JSType::CONSTANT_STRING;
}
inline bool IsSlicedString() const
{
return GetObjectType() == JSType::SLICED_STRING;
}
inline bool IsTreeString() const
{
return GetObjectType() == JSType::TREE_STRING;

View File

@ -329,6 +329,7 @@ bool JSSerializer::WriteTaggedObject(const JSHandle<JSTaggedValue> &value)
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING:
case JSType::SLICED_STRING:
return WriteEcmaString(value);
case JSType::JS_OBJECT:
return WritePlainObject(value);
@ -597,12 +598,12 @@ bool JSSerializer::WriteJSArray(const JSHandle<JSTaggedValue> &value)
bool JSSerializer::WriteEcmaString(const JSHandle<JSTaggedValue> &value)
{
JSHandle<EcmaString> strHandle = JSHandle<EcmaString>::Cast(value);
auto string = JSHandle<EcmaString>(thread_, EcmaStringAccessor::Flatten(thread_->GetEcmaVM(), strHandle));
auto string = EcmaStringAccessor::FlattenAllString(thread_->GetEcmaVM(), strHandle);
if (!WriteType(SerializationUID::ECMASTRING)) {
return false;
}
size_t length = EcmaStringAccessor(string).GetLength();
size_t length = string.GetLength();
if (!WriteInt(static_cast<int32_t>(length))) {
return false;
}
@ -611,19 +612,19 @@ bool JSSerializer::WriteEcmaString(const JSHandle<JSTaggedValue> &value)
return true;
}
bool isUtf8 = EcmaStringAccessor(string).IsUtf8();
bool isUtf8 = string.IsUtf8();
// write utf encode flag
if (!WriteBoolean(isUtf8)) {
return false;
}
if (isUtf8) {
const uint8_t *data = EcmaStringAccessor(string).GetDataUtf8();
const uint8_t *data = string.GetDataUtf8();
const uint8_t strEnd = '\0';
if (!WriteRawData(data, length) || !WriteRawData(&strEnd, sizeof(uint8_t))) {
return false;
}
} else {
const uint16_t *data = EcmaStringAccessor(string).GetDataUtf16();
const uint16_t *data = string.GetDataUtf16();
if (!WriteRawData(data, length * sizeof(uint16_t))) {
return false;
}

View File

@ -475,6 +475,11 @@ inline bool JSTaggedValue::IsTreeString() const
return IsHeapObject() && GetTaggedObject()->GetClass()->IsTreeString();
}
inline bool JSTaggedValue::IsSlicedString() const
{
return IsHeapObject() && GetTaggedObject()->GetClass()->IsSlicedString();
}
inline bool JSTaggedValue::IsBigInt() const
{
return IsHeapObject() && GetTaggedObject()->GetClass()->IsBigInt();

View File

@ -522,6 +522,7 @@ public:
bool IsLineString() const;
bool IsConstantString() const;
bool IsTreeString() const;
bool IsSlicedString() const;
bool IsStringOrSymbol() const;
bool IsTaggedArray() const;
bool IsDictionary() const;

View File

@ -338,6 +338,9 @@ public:
case JSType::TREE_STRING:
TreeEcmaString::Cast(object)->VisitRangeSlot(visitor);
break;
case JSType::SLICED_STRING:
SlicedString::Cast(object)->VisitRangeSlot(visitor);
break;
case JSType::JS_NATIVE_POINTER:
if (visitType == VisitType::SNAPSHOT_VISIT) {
JSNativePointer::Cast(object)->VisitRangeSlotForNative(visitor);

View File

@ -47,6 +47,13 @@ EcmaString *ObjectFactory::AllocOldSpaceLineStringObject(size_t size)
JSHClass::Cast(thread_->GlobalConstants()->GetLineStringClass().GetTaggedObject()), size));
}
EcmaString *ObjectFactory::AllocSlicedStringObject(MemSpaceType type)
{
NewObjectHook();
return reinterpret_cast<EcmaString *>(AllocObjectWithSpaceType(SlicedString::SIZE,
JSHClass::Cast(thread_->GlobalConstants()->GetSlicedStringClass().GetTaggedObject()), type));
}
EcmaString *ObjectFactory::AllocConstantStringObject(MemSpaceType type)
{
NewObjectHook();

View File

@ -534,6 +534,7 @@ public:
inline EcmaString *AllocLineStringObject(size_t size);
inline EcmaString *AllocOldSpaceLineStringObject(size_t size);
inline EcmaString *AllocNonMovableLineStringObject(size_t size);
inline EcmaString *AllocSlicedStringObject(MemSpaceType type);
inline EcmaString *AllocConstantStringObject(MemSpaceType type);
inline EcmaString *AllocTreeStringObject();

View File

@ -2138,7 +2138,7 @@ DEF_RUNTIME_STUBS(ContainerRBTreeForEach)
DEF_RUNTIME_STUBS(SlowFlattenString)
{
RUNTIME_STUBS_HEADER(SlowFlattenString);
JSHandle<TreeEcmaString> str = GetHArg<TreeEcmaString>(argv, argc, 0); // 0: means the zeroth parameter
JSHandle<EcmaString> str = GetHArg<EcmaString>(argv, argc, 0); // 0: means the zeroth parameter
return JSTaggedValue(EcmaStringAccessor::SlowFlatten(thread->GetEcmaVM(), str)).GetRawData();
}

View File

@ -782,7 +782,8 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
}
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING: {
case JSType::TREE_STRING:
case JSType::SLICED_STRING: {
DUMP_FOR_HANDLE(globalEnv->GetObjectFunction())
break;
}

View File

@ -120,10 +120,12 @@ HWTEST_F_L0(JSHClassTest, HasReferenceField)
JSHandle<JSHClass> obj3Class =
factory->NewEcmaHClass(TaggedArray::SIZE, JSType::JS_NATIVE_POINTER, nullHandle);
JSHandle<JSHClass> obj4Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::JS_OBJECT, nullHandle);
JSHandle<JSHClass> obj5Class = factory->NewEcmaHClass(TaggedArray::SIZE, JSType::SLICED_STRING, nullHandle);
EXPECT_FALSE(obj1Class->HasReferenceField());
EXPECT_TRUE(obj2Class->HasReferenceField());
EXPECT_FALSE(obj3Class->HasReferenceField());
EXPECT_TRUE(obj4Class->HasReferenceField());
EXPECT_TRUE(obj5Class->HasReferenceField());
}
HWTEST_F_L0(JSHClassTest, Clone)

View File

@ -183,6 +183,7 @@ group("ark_aot_ts_test") {
"stownbyvaluewithnameset",
"strictequal",
"strictnotequal",
"string",
"stsuperbyname",
"sub",
"supercall",

View File

@ -0,0 +1,18 @@
# Copyright (c) 2022 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_aot_test_action("string") {
deps = []
}

View File

@ -0,0 +1,21 @@
# Copyright (c) 2022 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.
52
4
5
52
5678901234567890
5
8
57

View File

@ -0,0 +1,52 @@
/*
* 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.
*/
declare function print(arg:any, arg1?:any):string;
class cpu {
public mode: number = 1;
constructor() {
this.mode = 4;
}
public static add(a: string):number {
let i : number = 3;
let b : string = a.substring(3);
print(b);
let d : number = b.charCodeAt(4);
print(a[i]);
print(b[i]);
return d;
}
}
function foo(a: string):number {
let b : string = a.substring(1);
let d : number = b.charCodeAt(1);
return d;
}
function foo1(a: string):number {
let i : number = 2;
let b : string = a.substring(1);
let d : number = b.charCodeAt(1);
print(a[i]);
print(b[i]);
return d;
}
var a : string = "12345678901234567890"
var b : string = a.substring(1);
print(foo(b));
print(foo1(b));
print(cpu.add(b));

View File

@ -17,3 +17,7 @@ true
true
false
Invalid string length
19981
肯访华:
djdjsajkdfalddgetg

View File

@ -45,4 +45,10 @@ try {
}
} catch (e) {
print(e.message);
}
}
let string1 = "fdjDJSAjkdfalDDGETG";
let string2 = string1.substring(1);
print(str1.charAt());
print(str2.charCodeAt());
print(str1.substr(2, 4));
print(string2.toLowerCase(2, 4));