Skip to content

Commit c7a0049

Browse files
bmeurerCommit Bot
authored andcommitted
[objects] Change String::length field to uint32_t.
This changes the Name::hash_field and Symbol::flags to uint32_t as well, so that both Symbols and Strings consume one fewer word on 64-bit architectures now. More importantly the access to String::length is always a 32-bit field load now, even with 31-bit Smis (i.e. on ARM or on 64-bit with pointer compression), so the access should be faster. Bug: v8:7065, v8:8171 Change-Id: I1a38f4470d62fbeba2b3bc5fcf4ecdbada7d6b8a Tbr: [email protected], [email protected], [email protected] Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng;luci.v8.try:v8_linux_noi18n_rel_ng Reviewed-on: https://chromium-review.googlesource.com/1224432 Reviewed-by: Benedikt Meurer <[email protected]> Commit-Queue: Benedikt Meurer <[email protected]> Cr-Commit-Position: refs/heads/master@{#55861}
1 parent ca894e0 commit c7a0049

19 files changed

Lines changed: 377 additions & 366 deletions

include/v8-internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ class Internals {
129129
// the implementation of v8.
130130
static const int kHeapObjectMapOffset = 0;
131131
static const int kMapInstanceTypeOffset = 1 * kApiPointerSize + kApiIntSize;
132-
static const int kStringResourceOffset = 3 * kApiPointerSize;
132+
static const int kStringResourceOffset =
133+
1 * kApiPointerSize + 2 * kApiIntSize;
133134

134135
static const int kOddballKindOffset = 4 * kApiPointerSize + kApiDoubleSize;
135136
static const int kForeignAddressOffset = kApiPointerSize;

src/accessors.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map,
7171
default:
7272
if (map->instance_type() < FIRST_NONSTRING_TYPE) {
7373
return CheckForName(isolate, name, isolate->factory()->length_string(),
74-
String::kLengthOffset, FieldIndex::kTagged, index);
74+
String::kLengthOffset, FieldIndex::kWord32, index);
7575
}
7676

7777
return false;

src/builtins/builtins-intl-gen.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
4141
Label call_c(this), return_string(this), runtime(this, Label::kDeferred);
4242

4343
// Early exit on empty strings.
44-
TNode<Smi> const length = LoadStringLengthAsSmi(string);
45-
GotoIf(SmiEqual(length, SmiConstant(0)), &return_string);
44+
TNode<Uint32T> const length = LoadStringLengthAsWord32(string);
45+
GotoIf(Word32Equal(length, Uint32Constant(0)), &return_string);
4646

4747
// Unpack strings if possible, and bail to runtime unless we get a one-byte
4848
// flat string.
@@ -60,7 +60,8 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
6060
Node* const dst = AllocateSeqOneByteString(context, length);
6161

6262
const int kMaxShortStringLength = 24; // Determined empirically.
63-
GotoIf(SmiGreaterThan(length, SmiConstant(kMaxShortStringLength)), &call_c);
63+
GotoIf(Uint32GreaterThan(length, Uint32Constant(kMaxShortStringLength)),
64+
&call_c);
6465

6566
{
6667
Node* const dst_ptr = PointerToSeqStringData(dst);
@@ -69,7 +70,7 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
6970

7071
Node* const start_address = to_direct.PointerToData(&call_c);
7172
TNode<IntPtrT> const end_address =
72-
Signed(IntPtrAdd(start_address, SmiUntag(length)));
73+
Signed(IntPtrAdd(start_address, ChangeUint32ToWord(length)));
7374

7475
Node* const to_lower_table_addr =
7576
ExternalConstant(ExternalReference::intl_to_latin1_lower_table());

src/builtins/builtins-object-gen.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,9 @@ void ObjectBuiltinsAssembler::ObjectAssignFast(TNode<Context> context,
535535
GotoIf(IsJSReceiverInstanceType(from_instance_type), &cont);
536536
GotoIfNot(IsStringInstanceType(from_instance_type), &done);
537537
{
538-
Branch(SmiEqual(LoadStringLengthAsSmi(CAST(from)), SmiConstant(0)), &done,
539-
slow);
538+
Branch(
539+
Word32Equal(LoadStringLengthAsWord32(CAST(from)), Int32Constant(0)),
540+
&done, slow);
540541
}
541542
BIND(&cont);
542543
}

src/builtins/builtins-regexp-gen.cc

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,7 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
11031103
Isolate* isolate = this->isolate();
11041104

11051105
TNode<IntPtrT> const int_one = IntPtrConstant(1);
1106-
TVARIABLE(Smi, var_length, SmiZero());
1106+
TVARIABLE(Uint32T, var_length, Uint32Constant(0));
11071107
TVARIABLE(IntPtrT, var_flags);
11081108

11091109
// First, count the number of characters we will need and check which flags
@@ -1115,13 +1115,13 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
11151115
Node* const flags_smi = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
11161116
var_flags = SmiUntag(flags_smi);
11171117

1118-
#define CASE_FOR_FLAG(FLAG) \
1119-
do { \
1120-
Label next(this); \
1121-
GotoIfNot(IsSetWord(var_flags.value(), FLAG), &next); \
1122-
var_length = SmiAdd(var_length.value(), SmiConstant(1)); \
1123-
Goto(&next); \
1124-
BIND(&next); \
1118+
#define CASE_FOR_FLAG(FLAG) \
1119+
do { \
1120+
Label next(this); \
1121+
GotoIfNot(IsSetWord(var_flags.value(), FLAG), &next); \
1122+
var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \
1123+
Goto(&next); \
1124+
BIND(&next); \
11251125
} while (false)
11261126

11271127
CASE_FOR_FLAG(JSRegExp::kGlobal);
@@ -1145,7 +1145,7 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
11451145
Label if_isflagset(this); \
11461146
BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \
11471147
BIND(&if_isflagset); \
1148-
var_length = SmiAdd(var_length.value(), SmiConstant(1)); \
1148+
var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \
11491149
var_flags = Signed(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \
11501150
Goto(&next); \
11511151
BIND(&next); \

src/builtins/builtins-string-gen.cc

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -549,8 +549,9 @@ TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) {
549549
}
550550

551551
TF_BUILTIN(StringCharAt, StringBuiltinsAssembler) {
552-
Node* receiver = Parameter(Descriptor::kReceiver);
553-
Node* position = Parameter(Descriptor::kPosition);
552+
TNode<String> receiver = CAST(Parameter(Descriptor::kReceiver));
553+
TNode<IntPtrT> position =
554+
UncheckedCast<IntPtrT>(Parameter(Descriptor::kPosition));
554555

555556
// Load the character code at the {position} from the {receiver}.
556557
TNode<Int32T> code = StringCharCodeAt(receiver, position);
@@ -601,7 +602,6 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
601602
Node* context = Parameter(Descriptor::kContext);
602603

603604
CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc));
604-
TNode<Smi> smi_argc = SmiTag(arguments.GetLength(INTPTR_PARAMETERS));
605605
// Check if we have exactly one argument (plus the implicit receiver), i.e.
606606
// if the parent frame is not an arguments adaptor frame.
607607
Label if_oneargument(this), if_notoneargument(this);
@@ -626,7 +626,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
626626
{
627627
Label two_byte(this);
628628
// Assume that the resulting string contains only one-byte characters.
629-
Node* one_byte_result = AllocateSeqOneByteString(context, smi_argc);
629+
Node* one_byte_result = AllocateSeqOneByteString(context, Unsigned(argc));
630630

631631
TVARIABLE(IntPtrT, var_max_index);
632632
var_max_index = IntPtrConstant(0);
@@ -660,7 +660,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
660660
// At least one of the characters in the string requires a 16-bit
661661
// representation. Allocate a SeqTwoByteString to hold the resulting
662662
// string.
663-
Node* two_byte_result = AllocateSeqTwoByteString(context, smi_argc);
663+
Node* two_byte_result = AllocateSeqTwoByteString(context, Unsigned(argc));
664664

665665
// Copy the characters that have already been put in the 8-bit string into
666666
// their corresponding positions in the new 16-bit string.
@@ -1191,8 +1191,6 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
11911191
TNode<Object> count = CAST(Parameter(Descriptor::kCount));
11921192
Node* const string =
11931193
ToThisString(context, receiver, "String.prototype.repeat");
1194-
Node* const is_stringempty =
1195-
SmiEqual(LoadStringLengthAsSmi(string), SmiConstant(0));
11961194

11971195
VARIABLE(
11981196
var_count, MachineRepresentation::kTagged,
@@ -1210,7 +1208,8 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
12101208
TNode<Smi> smi_count = CAST(var_count.value());
12111209
GotoIf(SmiLessThan(smi_count, SmiConstant(0)), &invalid_count);
12121210
GotoIf(SmiEqual(smi_count, SmiConstant(0)), &return_emptystring);
1213-
GotoIf(is_stringempty, &return_emptystring);
1211+
GotoIf(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)),
1212+
&return_emptystring);
12141213
GotoIf(SmiGreaterThan(smi_count, SmiConstant(String::kMaxLength)),
12151214
&invalid_string_length);
12161215
Return(CallBuiltin(Builtins::kStringRepeat, context, string, smi_count));
@@ -1228,7 +1227,8 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
12281227
&invalid_count);
12291228
GotoIf(Float64LessThan(number_value, Float64Constant(0.0)),
12301229
&invalid_count);
1231-
Branch(is_stringempty, &return_emptystring, &invalid_string_length);
1230+
Branch(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)),
1231+
&return_emptystring, &invalid_string_length);
12321232
}
12331233
}
12341234

@@ -1328,16 +1328,16 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
13281328
TNode<String> const subject_string = ToString_Inline(context, receiver);
13291329
TNode<String> const search_string = ToString_Inline(context, search);
13301330

1331-
TNode<Smi> const subject_length = LoadStringLengthAsSmi(subject_string);
1332-
TNode<Smi> const search_length = LoadStringLengthAsSmi(search_string);
1331+
TNode<IntPtrT> const subject_length = LoadStringLengthAsWord(subject_string);
1332+
TNode<IntPtrT> const search_length = LoadStringLengthAsWord(search_string);
13331333

13341334
// Fast-path single-char {search}, long cons {receiver}, and simple string
13351335
// {replace}.
13361336
{
13371337
Label next(this);
13381338

1339-
GotoIfNot(SmiEqual(search_length, SmiConstant(1)), &next);
1340-
GotoIfNot(SmiGreaterThan(subject_length, SmiConstant(0xFF)), &next);
1339+
GotoIfNot(WordEqual(search_length, IntPtrConstant(1)), &next);
1340+
GotoIfNot(IntPtrGreaterThan(subject_length, IntPtrConstant(0xFF)), &next);
13411341
GotoIf(TaggedIsSmi(replace), &next);
13421342
GotoIfNot(IsString(replace), &next);
13431343

@@ -1389,7 +1389,8 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
13891389
BIND(&next);
13901390
}
13911391

1392-
TNode<Smi> const match_end_index = SmiAdd(match_start_index, search_length);
1392+
TNode<Smi> const match_end_index =
1393+
SmiAdd(match_start_index, SmiFromIntPtr(search_length));
13931394

13941395
VARIABLE(var_result, MachineRepresentation::kTagged, EmptyStringConstant());
13951396

@@ -1441,7 +1442,7 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
14411442
{
14421443
Node* const suffix =
14431444
CallBuiltin(Builtins::kStringSubstring, context, subject_string,
1444-
SmiUntag(match_end_index), SmiUntag(subject_length));
1445+
SmiUntag(match_end_index), subject_length);
14451446
Node* const result = CallBuiltin(Builtins::kStringAdd_CheckNone, context,
14461447
var_result.value(), suffix);
14471448
Return(result);

0 commit comments

Comments
 (0)