Reduce calling count of String::charAt

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
Seonghyun Kim 2025-05-08 17:44:57 +09:00 committed by Patrick Kim
commit c2ef5b9e12
10 changed files with 60 additions and 54 deletions

View file

@ -344,9 +344,10 @@ static Value stringReplaceFastPathHelper(ExecutionState& state, String* string,
{
ASSERT(string && replaceString);
auto replaceStringBad = replaceString->bufferAccessData();
bool hasDollar = false;
for (size_t i = 0; i < replaceString->length(); i++) {
if (replaceString->charAt(i) == '$') {
for (size_t i = 0; i < replaceStringBad.length; i++) {
if (replaceStringBad.charAt(i) == '$') {
hasDollar = true;
break;
}
@ -358,8 +359,7 @@ static Value stringReplaceFastPathHelper(ExecutionState& state, String* string,
int32_t matchCount = result.m_matchResults.size();
builder.appendSubString(string, 0, result.m_matchResults[0][0].m_start, &state);
for (int32_t i = 0; i < matchCount; i++) {
String* res = replaceString;
builder.appendString(res, &state);
builder.appendString(replaceString, &state);
if (i < matchCount - 1) {
builder.appendSubString(string, result.m_matchResults[i][0].m_end, result.m_matchResults[i + 1][0].m_start, &state);
}
@ -370,11 +370,11 @@ static Value stringReplaceFastPathHelper(ExecutionState& state, String* string,
int32_t matchCount = result.m_matchResults.size();
builder.appendSubString(string, 0, result.m_matchResults[0][0].m_start, &state);
for (int32_t i = 0; i < matchCount; i++) {
for (unsigned j = 0; j < replaceString->length(); j++) {
if (replaceString->charAt(j) == '$' && (j + 1) < replaceString->length()) {
char16_t c = replaceString->charAt(j + 1);
for (unsigned j = 0; j < replaceStringBad.length; j++) {
if (replaceStringBad.charAt(j) == '$' && (j + 1) < replaceStringBad.length) {
char16_t c = replaceStringBad.charAt(j + 1);
if (c == '$') {
builder.appendChar(replaceString->charAt(j), &state);
builder.appendChar(replaceStringBad.charAt(j), &state);
} else if (c == '&') {
builder.appendSubString(string, result.m_matchResults[i][0].m_start, result.m_matchResults[i][0].m_end, &state);
} else if (c == '\'') {
@ -384,8 +384,8 @@ static Value stringReplaceFastPathHelper(ExecutionState& state, String* string,
} else if ('0' <= c && c <= '9') {
size_t idx = c - '0';
bool usePeek = false;
if (j + 2 < replaceString->length()) {
int peek = replaceString->charAt(j + 2) - '0';
if (j + 2 < replaceStringBad.length) {
int peek = replaceStringBad.charAt(j + 2) - '0';
if (0 <= peek && peek <= 9) {
idx *= 10;
idx += peek;
@ -412,7 +412,7 @@ static Value stringReplaceFastPathHelper(ExecutionState& state, String* string,
}
j++;
} else {
builder.appendChar(replaceString->charAt(j), &state);
builder.appendChar(replaceStringBad.charAt(j), &state);
}
}
if (i < matchCount - 1) {
@ -717,11 +717,18 @@ static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t a
splitMatchUsingStr = [](String* S, int q, String* R) -> Value {
int s = S->length();
int r = R->length();
if (q + r > s)
if (q + r > s) {
return Value(false);
for (int i = 0; i < r; i++)
if (S->charAt(q + i) != R->charAt(i))
}
auto sData = S->bufferAccessData();
auto rData = R->bufferAccessData();
for (int i = 0; i < r; i++) {
if (sData.charAt(q + i) != rData.charAt(i)) {
return Value(false);
}
}
return Value(q + r);
};
if (s == 0) {
@ -1410,8 +1417,9 @@ static String* createHTML(ExecutionState& state, Value string, String* tag, Stri
// ReturnIfAbrupt(V).
// Let escapedV be the String value that is the same as V except that each occurrence of the code unit 0x0022 (QUOTATION MARK) in V has been replaced with the six code unit sequence "&quot;".
StringBuilder sb;
for (size_t i = 0; i < V->length(); i++) {
char16_t ch = V->charAt(i);
auto vData = V->bufferAccessData();
for (size_t i = 0; i < vData.length; i++) {
char16_t ch = vData.charAt(i);
if (ch == 0x22) {
sb.appendString("&quot;");
} else {

View file

@ -220,12 +220,13 @@ ExtendedNodeLOC ByteCodeBlock::computeNodeLOC(StringView src, ExtendedNodeLOC so
size_t line = sourceElementStart.line;
size_t column = sourceElementStart.column;
size_t srcLength = src.length();
auto bad = src.bufferAccessData();
for (size_t i = 0; i < index && i < srcLength; i++) {
char16_t c = src.charAt(i);
char16_t c = bad.charAt(i);
column++;
if (EscargotLexer::isLineTerminator(c)) {
// skip \r\n
if (c == 13 && (i + 1 < index) && src.charAt(i + 1) == 10) {
if (c == 13 && (i + 1 < index) && bad.charAt(i + 1) == 10) {
i++;
}
line++;

View file

@ -487,21 +487,11 @@ ParserStringView Scanner::SmallScannerResult::relatedSource(const ParserStringVi
return ParserStringView(source, this->start, this->end);
}
StringView Scanner::SmallScannerResult::relatedSource(const StringView& source) const
{
return StringView(source, this->start, this->end);
}
ParserStringView Scanner::ScannerResult::relatedSource(const ParserStringView& source)
{
return ParserStringView(source, this->start, this->end);
}
StringView Scanner::ScannerResult::relatedSource(const StringView& source)
{
return StringView(source, this->start, this->end);
}
Value Scanner::ScannerResult::valueStringLiteralToValue(Scanner* scannerInstance)
{
ASSERT(this->type == Token::StringLiteralToken);

View file

@ -533,7 +533,6 @@ public:
}
ParserStringView relatedSource(const ParserStringView& source) const;
StringView relatedSource(const StringView& source) const;
};
// ScannerResult should be allocated on the stack by ALLOCA

View file

@ -1476,7 +1476,7 @@ public:
param = this->parsePatternWithDefault(builder, params);
}
for (size_t i = 0; i < params.size(); i++) {
AtomicString as(this->escargotContext, params[i].relatedSource(this->scanner->sourceAsNormalView));
AtomicString as(this->escargotContext, params[i].relatedSource(this->scanner->source));
this->validateParam(options, params[i], as);
}
options.params.push_back(builder.convertToParameterSyntaxNode(param));
@ -4233,7 +4233,7 @@ public:
this->throwUnexpectedToken(this->lookahead);
}
this->nextToken();
left = this->finalize(this->createNode(), builder.createIdentifierNode(AtomicString(this->escargotContext, keywordToken.relatedSource(this->scanner->sourceAsNormalView))));
left = this->finalize(this->createNode(), builder.createIdentifierNode(AtomicString(this->escargotContext, keywordToken.relatedSource(this->scanner->source))));
init = nullptr;
type = statementTypeForIn;
} else {

View file

@ -406,13 +406,14 @@ void StackTraceData::buildStackTrace(Context* context, StringBuilder& builder)
size_t preLineSoFar = 0;
size_t afterLineSoFar = 0;
auto bad = src->bufferAccessData();
size_t start = loc.index;
int64_t idx = (int64_t)start;
while (start - idx < preLineMax) {
if (idx == 0) {
break;
}
if (src->charAt((size_t)idx) == '\r' || src->charAt((size_t)idx) == '\n') {
if (bad.charAt((size_t)idx) == '\r' || bad.charAt((size_t)idx) == '\n') {
idx++;
break;
}
@ -422,27 +423,26 @@ void StackTraceData::buildStackTrace(Context* context, StringBuilder& builder)
idx = start;
while (idx - start < afterLineMax) {
if ((size_t)idx == src->length() - 1) {
if ((size_t)idx == bad.length - 1) {
break;
}
if (src->charAt((size_t)idx) == '\r' || src->charAt((size_t)idx) == '\n') {
if (bad.charAt((size_t)idx) == '\r' || bad.charAt((size_t)idx) == '\n') {
break;
}
idx++;
}
afterLineSoFar = idx;
if (preLineSoFar <= afterLineSoFar && preLineSoFar <= src->length() && afterLineSoFar <= src->length()) {
auto subSrc = src->substring(preLineSoFar, afterLineSoFar);
if (preLineSoFar <= afterLineSoFar && preLineSoFar <= bad.length && afterLineSoFar <= bad.length) {
builder.appendChar('\n');
builder.appendString(subSrc);
builder.appendSubString(src, preLineSoFar, afterLineSoFar);
builder.appendChar('\n');
std::string sourceCodePosition;
for (size_t i = preLineSoFar; i < start; i++) {
sourceCodePosition += " ";
}
sourceCodePosition += "^";
builder.appendString(String::fromUTF8(sourceCodePosition.data(), sourceCodePosition.length()));
builder.appendString(String::fromASCII(sourceCodePosition.data(), sourceCodePosition.length()));
}
}
}

View file

@ -54,7 +54,6 @@
#include "bignum-dtoa.h"
namespace Escargot {
MAY_THREAD_LOCAL String* String::emptyString;
std::vector<std::string> split(const std::string& s, char seperator)

View file

@ -26,7 +26,6 @@
#include <string>
namespace Escargot {
// A type to hold a single Latin-1 character.
typedef unsigned char LChar;
@ -416,8 +415,9 @@ public:
return false;
}
auto bad = bufferAccessData();
for (size_t i = 0; i < srcLen; i++) {
if (src[i] != charAt(i)) {
if (src[i] != bad.charAt(i)) {
return false;
}
}

View file

@ -71,9 +71,10 @@ public:
UTF16StringData ret;
size_t len = length();
ret.resizeWithUninitializedValues(len);
auto bad = bufferAccessData();
for (size_t i = 0; i < len; i++) {
ret[i] = charAt(i);
ret[i] = bad.charAt(i);
}
return ret;

View file

@ -35,11 +35,13 @@ class String {
public:
String()
: m_impl()
, m_implBufferAccessData(Escargot::String::emptyString->bufferAccessData())
{
}
String(::Escargot::String* impl)
: m_impl(impl)
, m_implBufferAccessData(impl->bufferAccessData())
{
}
@ -48,7 +50,7 @@ public:
if (isNull()) {
return 0;
}
return m_impl->charAt(idx);
return m_implBufferAccessData.charAt(idx);
}
ALWAYS_INLINE size_t length() const
@ -56,7 +58,7 @@ public:
if (isNull()) {
return 0;
}
return m_impl->length();
return m_implBufferAccessData.length;
}
bool equals(const String& src) const
@ -75,10 +77,10 @@ public:
if (isNull()) {
return 0;
}
if (m_impl->is8Bit()) {
return StringHasher::computeHashAndMaskTop8Bits(m_impl->characters8(), m_impl->length());
if (m_implBufferAccessData.has8BitContent) {
return StringHasher::computeHashAndMaskTop8Bits(m_implBufferAccessData.bufferAs8Bit, m_implBufferAccessData.length);
} else {
return StringHasher::computeHashAndMaskTop8Bits(m_impl->characters16(), m_impl->length());
return StringHasher::computeHashAndMaskTop8Bits(m_implBufferAccessData.bufferAs16Bit, m_implBufferAccessData.length);
}
}
@ -87,8 +89,13 @@ public:
if (isNull()) {
return false;
}
char b[2] = { c, 0x0 };
return m_impl->contains(b);
for (size_t i = 0; i < m_implBufferAccessData.length; i ++) {
if (m_implBufferAccessData.charAt(i) == c) {
return true;
}
}
return false;
}
bool isNull() const
@ -101,7 +108,7 @@ public:
if (isNull()) {
return true;
}
return m_impl->is8Bit();
return m_implBufferAccessData.has8BitContent;
}
template <typename Any>
@ -111,9 +118,9 @@ public:
return nullptr;
}
if (is8Bit()) {
return (Any*)m_impl->characters8();
return (Any*)m_implBufferAccessData.bufferAs8Bit;
} else {
return (Any*)m_impl->characters16();
return (Any*)m_implBufferAccessData.bufferAs16Bit;
}
}
@ -122,7 +129,7 @@ public:
if (isNull()) {
return nullptr;
}
return m_impl->characters8();
return reinterpret_cast<const LChar*>(m_implBufferAccessData.bufferAs8Bit);
}
ALWAYS_INLINE const char16_t* characters16() const
@ -130,7 +137,7 @@ public:
if (isNull()) {
return nullptr;
}
return m_impl->characters16();
return m_implBufferAccessData.bufferAs16Bit;
}
ALWAYS_INLINE::Escargot::String* impl()
@ -149,6 +156,7 @@ public:
private:
Optional<::Escargot::String*> m_impl;
::Escargot::StringBufferAccessData m_implBufferAccessData;
};
using StringView = const String&;