mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2025-02-26 15:28:33 +00:00
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:
parent
09412f71ca
commit
fa4b637a68
@ -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));
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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, ¬LineString);
|
||||
Bind(¬LineString);
|
||||
{
|
||||
Label isTreeString(env);
|
||||
Label notTreeString(env);
|
||||
Label isSlicedString(env);
|
||||
Branch(IsTreeString(str), &isTreeString, ¬TreeString);
|
||||
Bind(&isTreeString);
|
||||
{
|
||||
Label isFlat(env);
|
||||
Label notFlat(env);
|
||||
Branch(TreeStringIsFlat(str), &isFlat, ¬Flat);
|
||||
Bind(&isFlat);
|
||||
{
|
||||
flatString_.WriteVariable(GetFirstFromTreeString(str));
|
||||
Jump(fastPath);
|
||||
}
|
||||
Bind(¬Flat);
|
||||
{
|
||||
flatString_.WriteVariable(CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str }));
|
||||
Jump(fastPath);
|
||||
}
|
||||
}
|
||||
Bind(¬TreeString);
|
||||
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
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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, ¬Flat);
|
||||
Bind(&isFlat);
|
||||
{
|
||||
result = GetFirstFromTreeString(str);
|
||||
Jump(&exit);
|
||||
}
|
||||
Bind(¬Flat);
|
||||
{
|
||||
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, ¬LineString);
|
||||
Bind(¬LineString);
|
||||
{
|
||||
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();
|
||||
|
@ -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);
|
||||
|
@ -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, ¬TreeString);
|
||||
builder_.Bind(&isTreeString);
|
||||
{
|
||||
Label isFlat(&builder_);
|
||||
Label notFlat(&builder_);
|
||||
builder_.Branch(builder_.TreeStringIsFlat(str), &isFlat, ¬Flat);
|
||||
builder_.Branch(builder_.TreeStringIsFlat(str), &isFlat, &needFlat);
|
||||
builder_.Bind(&isFlat);
|
||||
{
|
||||
result = builder_.GetFirstFromTreeString(str);
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
builder_.Bind(¬Flat);
|
||||
{
|
||||
result = LowerCallRuntime(glue, gate, RTSTUB_ID(SlowFlattenString), { str }, true);
|
||||
builder_.Jump(&exit);
|
||||
}
|
||||
}
|
||||
|
||||
builder_.Bind(¬TreeString);
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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) \
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -183,6 +183,7 @@ group("ark_aot_ts_test") {
|
||||
"stownbyvaluewithnameset",
|
||||
"strictequal",
|
||||
"strictnotequal",
|
||||
"string",
|
||||
"stsuperbyname",
|
||||
"sub",
|
||||
"supercall",
|
||||
|
18
test/aottest/string/BUILD.gn
Normal file
18
test/aottest/string/BUILD.gn
Normal 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 = []
|
||||
}
|
21
test/aottest/string/expect_output.txt
Normal file
21
test/aottest/string/expect_output.txt
Normal 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
|
52
test/aottest/string/string.ts
Normal file
52
test/aottest/string/string.ts
Normal 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));
|
||||
|
@ -17,3 +17,7 @@ true
|
||||
true
|
||||
false
|
||||
Invalid string length
|
||||
不
|
||||
19981
|
||||
肯访华:
|
||||
djdjsajkdfalddgetg
|
||||
|
@ -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));
|
Loading…
x
Reference in New Issue
Block a user