Commit a03cec2c authored by Benedikt Meurer's avatar Benedikt Meurer Committed by Commit Bot

Reland "[objects] Change String::length field to uint32_t."

This is a reland of 1f1eb625, the
breakage on the GCStress bot seems to be unrelated (maybe flushed
out by this change). We decided to reland to figure out whether it's
a random flake or really triggered by this particular change.

Original change's description:
> [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
> Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng;luci.v8.try:v8_linux_noi18n_rel_ng
> Change-Id: I5523deb1f84ece91fa2fea775d50318bd1300493
> Reviewed-on: https://chromium-review.googlesource.com/1221288
> Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#55825}

Bug: v8:7065, v8:8171
Tbr: tebbi@chromium.org, yangguo@chromium.org, ishell@chromium.org, ulan@chromium.org
Change-Id: I2be24ac018591c04c826e7e8db82e007b738d156
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/1222308Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55838}
parent bd69d64d
......@@ -129,7 +129,8 @@ class Internals {
// the implementation of v8.
static const int kHeapObjectMapOffset = 0;
static const int kMapInstanceTypeOffset = 1 * kApiPointerSize + kApiIntSize;
static const int kStringResourceOffset = 3 * kApiPointerSize;
static const int kStringResourceOffset =
1 * kApiPointerSize + 2 * kApiIntSize;
static const int kOddballKindOffset = 4 * kApiPointerSize + kApiDoubleSize;
static const int kForeignAddressOffset = kApiPointerSize;
......
......@@ -71,7 +71,7 @@ bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map,
default:
if (map->instance_type() < FIRST_NONSTRING_TYPE) {
return CheckForName(isolate, name, isolate->factory()->length_string(),
String::kLengthOffset, FieldIndex::kTagged, index);
String::kLengthOffset, FieldIndex::kWord32, index);
}
return false;
......
......@@ -41,8 +41,8 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
Label call_c(this), return_string(this), runtime(this, Label::kDeferred);
// Early exit on empty strings.
TNode<Smi> const length = LoadStringLengthAsSmi(string);
GotoIf(SmiEqual(length, SmiConstant(0)), &return_string);
TNode<Uint32T> const length = LoadStringLengthAsWord32(string);
GotoIf(Word32Equal(length, Uint32Constant(0)), &return_string);
// Unpack strings if possible, and bail to runtime unless we get a one-byte
// flat string.
......@@ -60,7 +60,8 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
Node* const dst = AllocateSeqOneByteString(context, length);
const int kMaxShortStringLength = 24; // Determined empirically.
GotoIf(SmiGreaterThan(length, SmiConstant(kMaxShortStringLength)), &call_c);
GotoIf(Uint32GreaterThan(length, Uint32Constant(kMaxShortStringLength)),
&call_c);
{
Node* const dst_ptr = PointerToSeqStringData(dst);
......@@ -69,7 +70,7 @@ TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
Node* const start_address = to_direct.PointerToData(&call_c);
TNode<IntPtrT> const end_address =
Signed(IntPtrAdd(start_address, SmiUntag(length)));
Signed(IntPtrAdd(start_address, ChangeUint32ToWord(length)));
Node* const to_lower_table_addr =
ExternalConstant(ExternalReference::intl_to_latin1_lower_table());
......
......@@ -536,8 +536,9 @@ void ObjectBuiltinsAssembler::ObjectAssignFast(TNode<Context> context,
GotoIf(IsJSReceiverInstanceType(from_instance_type), &cont);
GotoIfNot(IsStringInstanceType(from_instance_type), &done);
{
Branch(SmiEqual(LoadStringLengthAsSmi(CAST(from)), SmiConstant(0)), &done,
slow);
Branch(
Word32Equal(LoadStringLengthAsWord32(CAST(from)), Int32Constant(0)),
&done, slow);
}
BIND(&cont);
}
......
......@@ -1103,7 +1103,7 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
Isolate* isolate = this->isolate();
TNode<IntPtrT> const int_one = IntPtrConstant(1);
TVARIABLE(Smi, var_length, SmiZero());
TVARIABLE(Uint32T, var_length, Uint32Constant(0));
TVARIABLE(IntPtrT, var_flags);
// First, count the number of characters we will need and check which flags
......@@ -1115,13 +1115,13 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
Node* const flags_smi = LoadObjectField(regexp, JSRegExp::kFlagsOffset);
var_flags = SmiUntag(flags_smi);
#define CASE_FOR_FLAG(FLAG) \
do { \
Label next(this); \
GotoIfNot(IsSetWord(var_flags.value(), FLAG), &next); \
var_length = SmiAdd(var_length.value(), SmiConstant(1)); \
Goto(&next); \
BIND(&next); \
#define CASE_FOR_FLAG(FLAG) \
do { \
Label next(this); \
GotoIfNot(IsSetWord(var_flags.value(), FLAG), &next); \
var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \
Goto(&next); \
BIND(&next); \
} while (false)
CASE_FOR_FLAG(JSRegExp::kGlobal);
......@@ -1145,7 +1145,7 @@ Node* RegExpBuiltinsAssembler::FlagsGetter(Node* const context,
Label if_isflagset(this); \
BranchIfToBooleanIsTrue(flag, &if_isflagset, &next); \
BIND(&if_isflagset); \
var_length = SmiAdd(var_length.value(), SmiConstant(1)); \
var_length = Uint32Add(var_length.value(), Uint32Constant(1)); \
var_flags = Signed(WordOr(var_flags.value(), IntPtrConstant(FLAG))); \
Goto(&next); \
BIND(&next); \
......
......@@ -585,8 +585,9 @@ TF_BUILTIN(StringGreaterThanOrEqual, StringBuiltinsAssembler) {
}
TF_BUILTIN(StringCharAt, StringBuiltinsAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
Node* position = Parameter(Descriptor::kPosition);
TNode<String> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<IntPtrT> position =
UncheckedCast<IntPtrT>(Parameter(Descriptor::kPosition));
// Load the character code at the {position} from the {receiver}.
TNode<Int32T> code = StringCharCodeAt(receiver, position);
......@@ -637,7 +638,6 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
Node* context = Parameter(Descriptor::kContext);
CodeStubArguments arguments(this, ChangeInt32ToIntPtr(argc));
TNode<Smi> smi_argc = SmiTag(arguments.GetLength(INTPTR_PARAMETERS));
// Check if we have exactly one argument (plus the implicit receiver), i.e.
// if the parent frame is not an arguments adaptor frame.
Label if_oneargument(this), if_notoneargument(this);
......@@ -662,7 +662,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
{
Label two_byte(this);
// Assume that the resulting string contains only one-byte characters.
Node* one_byte_result = AllocateSeqOneByteString(context, smi_argc);
Node* one_byte_result = AllocateSeqOneByteString(context, Unsigned(argc));
TVARIABLE(IntPtrT, var_max_index);
var_max_index = IntPtrConstant(0);
......@@ -696,7 +696,7 @@ TF_BUILTIN(StringFromCharCode, CodeStubAssembler) {
// At least one of the characters in the string requires a 16-bit
// representation. Allocate a SeqTwoByteString to hold the resulting
// string.
Node* two_byte_result = AllocateSeqTwoByteString(context, smi_argc);
Node* two_byte_result = AllocateSeqTwoByteString(context, Unsigned(argc));
// Copy the characters that have already been put in the 8-bit string into
// their corresponding positions in the new 16-bit string.
......@@ -1227,8 +1227,6 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
TNode<Object> count = CAST(Parameter(Descriptor::kCount));
Node* const string =
ToThisString(context, receiver, "String.prototype.repeat");
Node* const is_stringempty =
SmiEqual(LoadStringLengthAsSmi(string), SmiConstant(0));
VARIABLE(
var_count, MachineRepresentation::kTagged,
......@@ -1246,7 +1244,8 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
TNode<Smi> smi_count = CAST(var_count.value());
GotoIf(SmiLessThan(smi_count, SmiConstant(0)), &invalid_count);
GotoIf(SmiEqual(smi_count, SmiConstant(0)), &return_emptystring);
GotoIf(is_stringempty, &return_emptystring);
GotoIf(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)),
&return_emptystring);
GotoIf(SmiGreaterThan(smi_count, SmiConstant(String::kMaxLength)),
&invalid_string_length);
Return(CallBuiltin(Builtins::kStringRepeat, context, string, smi_count));
......@@ -1264,7 +1263,8 @@ TF_BUILTIN(StringPrototypeRepeat, StringBuiltinsAssembler) {
&invalid_count);
GotoIf(Float64LessThan(number_value, Float64Constant(0.0)),
&invalid_count);
Branch(is_stringempty, &return_emptystring, &invalid_string_length);
Branch(Word32Equal(LoadStringLengthAsWord32(string), Int32Constant(0)),
&return_emptystring, &invalid_string_length);
}
}
......@@ -1367,16 +1367,16 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
TNode<String> const subject_string = ToString_Inline(context, receiver);
TNode<String> const search_string = ToString_Inline(context, search);
TNode<Smi> const subject_length = LoadStringLengthAsSmi(subject_string);
TNode<Smi> const search_length = LoadStringLengthAsSmi(search_string);
TNode<IntPtrT> const subject_length = LoadStringLengthAsWord(subject_string);
TNode<IntPtrT> const search_length = LoadStringLengthAsWord(search_string);
// Fast-path single-char {search}, long cons {receiver}, and simple string
// {replace}.
{
Label next(this);
GotoIfNot(SmiEqual(search_length, SmiConstant(1)), &next);
GotoIfNot(SmiGreaterThan(subject_length, SmiConstant(0xFF)), &next);
GotoIfNot(WordEqual(search_length, IntPtrConstant(1)), &next);
GotoIfNot(IntPtrGreaterThan(subject_length, IntPtrConstant(0xFF)), &next);
GotoIf(TaggedIsSmi(replace), &next);
GotoIfNot(IsString(replace), &next);
......@@ -1428,7 +1428,8 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
BIND(&next);
}
TNode<Smi> const match_end_index = SmiAdd(match_start_index, search_length);
TNode<Smi> const match_end_index =
SmiAdd(match_start_index, SmiFromIntPtr(search_length));
Callable stringadd_callable =
CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
......@@ -1483,7 +1484,7 @@ TF_BUILTIN(StringPrototypeReplace, StringBuiltinsAssembler) {
{
Node* const suffix =
CallBuiltin(Builtins::kStringSubstring, context, subject_string,
SmiUntag(match_end_index), SmiUntag(subject_length));
SmiUntag(match_end_index), subject_length);
Node* const result =
CallStub(stringadd_callable, context, var_result.value(), suffix);
Return(result);
......
This diff is collapsed.
......@@ -958,10 +958,12 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<Uint32T> LoadNameHash(SloppyTNode<Name> name,
Label* if_hash_not_computed = nullptr);
// Load length field of a String object as intptr_t value.
TNode<IntPtrT> LoadStringLengthAsWord(SloppyTNode<String> object);
// Load length field of a String object as Smi value.
TNode<Smi> LoadStringLengthAsSmi(SloppyTNode<String> object);
TNode<Smi> LoadStringLengthAsSmi(SloppyTNode<String> string);
// Load length field of a String object as intptr_t value.
TNode<IntPtrT> LoadStringLengthAsWord(SloppyTNode<String> string);
// Load length field of a String object as uint32_t value.
TNode<Uint32T> LoadStringLengthAsWord32(SloppyTNode<String> string);
// Loads a pointer to the sequential String char array.
Node* PointerToSeqStringData(Node* seq_string);
// Load value field of a JSValue object.
......@@ -1329,46 +1331,46 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<UintPtrT> LoadBigIntDigit(TNode<BigInt> bigint, int digit_index);
// Allocate a SeqOneByteString with the given length.
TNode<String> AllocateSeqOneByteString(int length,
TNode<String> AllocateSeqOneByteString(uint32_t length,
AllocationFlags flags = kNone);
TNode<String> AllocateSeqOneByteString(Node* context, TNode<Smi> length,
TNode<String> AllocateSeqOneByteString(Node* context, TNode<Uint32T> length,
AllocationFlags flags = kNone);
// Allocate a SeqTwoByteString with the given length.
TNode<String> AllocateSeqTwoByteString(int length,
TNode<String> AllocateSeqTwoByteString(uint32_t length,
AllocationFlags flags = kNone);
TNode<String> AllocateSeqTwoByteString(Node* context, TNode<Smi> length,
TNode<String> AllocateSeqTwoByteString(Node* context, TNode<Uint32T> length,
AllocationFlags flags = kNone);
// Allocate a SlicedOneByteString with the given length, parent and offset.
// |length| and |offset| are expected to be tagged.
TNode<String> AllocateSlicedOneByteString(TNode<Smi> length,
TNode<String> AllocateSlicedOneByteString(TNode<Uint32T> length,
TNode<String> parent,
TNode<Smi> offset);
// Allocate a SlicedTwoByteString with the given length, parent and offset.
// |length| and |offset| are expected to be tagged.
TNode<String> AllocateSlicedTwoByteString(TNode<Smi> length,
TNode<String> AllocateSlicedTwoByteString(TNode<Uint32T> length,
TNode<String> parent,
TNode<Smi> offset);
// Allocate a one-byte ConsString with the given length, first and second
// parts. |length| is expected to be tagged, and |first| and |second| are
// expected to be one-byte strings.
TNode<String> AllocateOneByteConsString(TNode<Smi> length,
TNode<String> AllocateOneByteConsString(TNode<Uint32T> length,
TNode<String> first,
TNode<String> second,
AllocationFlags flags = kNone);
// Allocate a two-byte ConsString with the given length, first and second
// parts. |length| is expected to be tagged, and |first| and |second| are
// expected to be two-byte strings.
TNode<String> AllocateTwoByteConsString(TNode<Smi> length,
TNode<String> AllocateTwoByteConsString(TNode<Uint32T> length,
TNode<String> first,
TNode<String> second,
AllocationFlags flags = kNone);
// Allocate an appropriate one- or two-byte ConsString with the first and
// second parts specified by |left| and |right|.
TNode<String> NewConsString(TNode<Smi> length, TNode<String> left,
TNode<String> NewConsString(TNode<Uint32T> length, TNode<String> left,
TNode<String> right,
AllocationFlags flags = kNone);
......@@ -2990,11 +2992,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Label* bailout);
TNode<String> AllocateSlicedString(Heap::RootListIndex map_root_index,
TNode<Smi> length, TNode<String> parent,
TNode<Smi> offset);
TNode<Uint32T> length,
TNode<String> parent, TNode<Smi> offset);
TNode<String> AllocateConsString(Heap::RootListIndex map_root_index,
TNode<Smi> length, TNode<String> first,
TNode<Uint32T> length, TNode<String> first,
TNode<String> second, AllocationFlags flags);
// Allocate a MutableHeapNumber without initializing its value.
......@@ -3018,7 +3020,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<String> AllocAndCopyStringCharacters(Node* from,
Node* from_instance_type,
TNode<IntPtrT> from_index,
TNode<Smi> character_count);
TNode<IntPtrT> character_count);
static const int kElementLoopUnrollThreshold = 8;
......
......@@ -611,7 +611,7 @@ FieldAccess AccessBuilder::ForStringLength() {
Handle<Name>(),
MaybeHandle<Map>(),
TypeCache::Get().kStringLengthType,
MachineType::TaggedSigned(),
MachineType::Uint32(),
kNoWriteBarrier};
return access;
}
......
......@@ -910,6 +910,11 @@ class V8_EXPORT_PRIVATE CodeAssembler {
Int32Add(static_cast<Node*>(left), static_cast<Node*>(right)));
}
TNode<Uint32T> Uint32Add(TNode<Uint32T> left, TNode<Uint32T> right) {
return Unsigned(
Int32Add(static_cast<Node*>(left), static_cast<Node*>(right)));
}
TNode<WordT> IntPtrAdd(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
TNode<WordT> IntPtrSub(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
TNode<WordT> IntPtrMul(SloppyTNode<WordT> left, SloppyTNode<WordT> right);
......
......@@ -2790,7 +2790,7 @@ Node* EffectControlLinearizer::LowerNewConsString(Node* node) {
Node* result = __ Allocate(NOT_TENURED, __ Int32Constant(ConsString::kSize));
__ StoreField(AccessBuilder::ForMap(), result, result_map);
__ StoreField(AccessBuilder::ForNameHashField(), result,
jsgraph()->Int32Constant(Name::kEmptyHashField));
__ Int32Constant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), result, length);
__ StoreField(AccessBuilder::ForConsStringFirst(), result, first);
__ StoreField(AccessBuilder::ForConsStringSecond(), result, second);
......@@ -3063,9 +3063,9 @@ Node* EffectControlLinearizer::LowerStringFromSingleCharCode(Node* node) {
__ StoreField(AccessBuilder::ForMap(), vtrue2,
__ HeapConstant(factory()->one_byte_string_map()));
__ StoreField(AccessBuilder::ForNameHashField(), vtrue2,
__ IntPtrConstant(Name::kEmptyHashField));
__ Int32Constant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), vtrue2,
__ SmiConstant(1));
__ Int32Constant(1));
__ Store(
StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier),
vtrue2,
......@@ -3087,8 +3087,9 @@ Node* EffectControlLinearizer::LowerStringFromSingleCharCode(Node* node) {
__ StoreField(AccessBuilder::ForMap(), vfalse1,
__ HeapConstant(factory()->string_map()));
__ StoreField(AccessBuilder::ForNameHashField(), vfalse1,
__ IntPtrConstant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), vfalse1, __ SmiConstant(1));
__ Int32Constant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), vfalse1,
__ Int32Constant(1));
__ Store(
StoreRepresentation(MachineRepresentation::kWord16, kNoWriteBarrier),
vfalse1,
......@@ -3186,9 +3187,9 @@ Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) {
__ StoreField(AccessBuilder::ForMap(), vtrue2,
__ HeapConstant(factory()->one_byte_string_map()));
__ StoreField(AccessBuilder::ForNameHashField(), vtrue2,
__ IntPtrConstant(Name::kEmptyHashField));
__ Int32Constant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), vtrue2,
__ SmiConstant(1));
__ Int32Constant(1));
__ Store(
StoreRepresentation(MachineRepresentation::kWord8, kNoWriteBarrier),
vtrue2,
......@@ -3212,7 +3213,7 @@ Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) {
__ StoreField(AccessBuilder::ForNameHashField(), vfalse1,
__ IntPtrConstant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), vfalse1,
__ SmiConstant(1));
__ Int32Constant(1));
__ Store(
StoreRepresentation(MachineRepresentation::kWord16, kNoWriteBarrier),
vfalse1,
......@@ -3257,8 +3258,9 @@ Node* EffectControlLinearizer::LowerStringFromSingleCodePoint(Node* node) {
__ StoreField(AccessBuilder::ForMap(), vfalse0,
__ HeapConstant(factory()->string_map()));
__ StoreField(AccessBuilder::ForNameHashField(), vfalse0,
__ IntPtrConstant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), vfalse0, __ SmiConstant(2));
__ Int32Constant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), vfalse0,
__ Int32Constant(2));
__ Store(
StoreRepresentation(MachineRepresentation::kWord32, kNoWriteBarrier),
vfalse0,
......
......@@ -121,13 +121,7 @@ class VirtualObject : public Dependable {
typedef ZoneVector<Variable>::const_iterator const_iterator;
VirtualObject(VariableTracker* var_states, Id id, int size);
Maybe<Variable> FieldAt(int offset) const {
if (offset % kPointerSize != 0) {
// We do not support fields that are not word-aligned. Bail out by
// treating the object as escaping. This can only happen for
// {Name::kHashFieldOffset} on 64bit big endian architectures.
DCHECK_EQ(Name::kHashFieldOffset, offset);
return Nothing<Variable>();
}
CHECK_EQ(0, offset % kPointerSize);
CHECK(!HasEscaped());
if (offset >= size()) {
// TODO(tebbi): Reading out-of-bounds can only happen in unreachable
......
......@@ -2338,9 +2338,9 @@ class RepresentationSelector {
MachineRepresentation::kTaggedPointer);
}
case IrOpcode::kNewConsString: {
ProcessInput(node, 0, UseInfo::TaggedSigned()); // length
ProcessInput(node, 1, UseInfo::AnyTagged()); // first
ProcessInput(node, 2, UseInfo::AnyTagged()); // second
ProcessInput(node, 0, UseInfo::TruncatingWord32()); // length
ProcessInput(node, 1, UseInfo::AnyTagged()); // first
ProcessInput(node, 2, UseInfo::AnyTagged()); // second
SetOutput(node, MachineRepresentation::kTaggedPointer);
return;
}
......@@ -2393,8 +2393,7 @@ class RepresentationSelector {
// TODO(bmeurer): The input representation should be TaggedPointer.
// Fix this once we have a dedicated StringConcat/JSStringAdd
// operator, which marks it's output as TaggedPointer properly.
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedSigned);
VisitUnop(node, UseInfo::AnyTagged(), MachineRepresentation::kWord32);
return;
}
case IrOpcode::kStringSubstring: {
......
......@@ -2093,7 +2093,7 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
Comment("check if string");
GotoIfNot(IsStringInstanceType(instance_type), slow);
Comment("load string character");
Node* length = LoadAndUntagObjectField(receiver, String::kLengthOffset);
TNode<IntPtrT> length = LoadStringLengthAsWord(receiver);
GotoIfNot(UintPtrLessThan(index, length), slow);
IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
TailCallBuiltin(Builtins::kStringCharAt, NoContextConstant(), receiver,
......
......@@ -19,24 +19,25 @@ CAST_ACCESSOR(Name)
CAST_ACCESSOR(Symbol)
ACCESSORS(Symbol, name, Object, kNameOffset)
SMI_ACCESSORS(Symbol, flags, kFlagsOffset)
BOOL_ACCESSORS(Symbol, flags, is_private, kPrivateBit)
BOOL_ACCESSORS(Symbol, flags, is_well_known_symbol, kWellKnownSymbolBit)
BOOL_ACCESSORS(Symbol, flags, is_public, kPublicBit)
BOOL_ACCESSORS(Symbol, flags, is_interesting_symbol, kInterestingSymbolBit)
INT_ACCESSORS(Symbol, flags, kFlagsOffset)
BIT_FIELD_ACCESSORS(Symbol, flags, is_private, Symbol::IsPrivateBit)
BIT_FIELD_ACCESSORS(Symbol, flags, is_well_known_symbol,
Symbol::IsWellKnownSymbolBit)
BIT_FIELD_ACCESSORS(Symbol, flags, is_public, Symbol::IsPublicBit)
BIT_FIELD_ACCESSORS(Symbol, flags, is_interesting_symbol,
Symbol::IsInterestingSymbolBit)
bool Symbol::is_private_field() const {
bool value = BooleanBit::get(flags(), kPrivateFieldBit);
bool value = Symbol::IsPrivateFieldBit::decode(flags());
DCHECK_IMPLIES(value, is_private());
return value;
}
void Symbol::set_is_private_field() {
int old_value = flags();
// TODO(gsathya): Re-order the bits to have these next to each other
// and just do the bit shifts once.
set_flags(BooleanBit::set(old_value, kPrivateBit, true) |
BooleanBit::set(old_value, kPrivateFieldBit, true));
set_flags(Symbol::IsPrivateBit::update(flags(), true));
set_flags(Symbol::IsPrivateFieldBit::update(flags(), true));
}
bool Name::IsUniqueName() const {
......@@ -51,13 +52,6 @@ uint32_t Name::hash_field() {
void Name::set_hash_field(uint32_t value) {
WRITE_UINT32_FIELD(this, kHashFieldOffset, value);
#if V8_HOST_ARCH_64_BIT
#if V8_TARGET_LITTLE_ENDIAN
WRITE_UINT32_FIELD(this, kHashFieldSlot + kInt32Size, 0);
#else
WRITE_UINT32_FIELD(this, kHashFieldSlot, 0);
#endif
#endif
}
bool Name::Equals(Name* other) {
......
......@@ -67,13 +67,8 @@ class Name : public HeapObject {
int NameShortPrint(Vector<char> str);
// Layout description.
static const int kHashFieldSlot = HeapObject::kHeaderSize;
#if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT
static const int kHashFieldOffset = kHashFieldSlot;
#else
static const int kHashFieldOffset = kHashFieldSlot + kInt32Size;
#endif
static const int kSize = kHashFieldSlot + kPointerSize;
static const int kHashFieldOffset = HeapObject::kHeaderSize;
static const int kHeaderSize = kHashFieldOffset + kInt32Size;
// Mask constant for checking if a name has a computed hash code
// and if it is a string that is an array index. The least significant bit
......@@ -181,18 +176,22 @@ class Symbol : public Name {
DECL_VERIFIER(Symbol)
// Layout description.
static const int kNameOffset = Name::kSize;
static const int kFlagsOffset = kNameOffset + kPointerSize;
static const int kSize = kFlagsOffset + kPointerSize;
// Flags layout.
static const int kPrivateBit = 0;
static const int kWellKnownSymbolBit = 1;
static const int kPublicBit = 2;
static const int kInterestingSymbolBit = 3;
static const int kPrivateFieldBit = 4;
typedef FixedBodyDescriptor<kNameOffset, kFlagsOffset, kSize> BodyDescriptor;
static const int kFlagsOffset = Name::kHeaderSize;
static const int kNameOffset = kFlagsOffset + kInt32Size;
static const int kSize = kNameOffset + kPointerSize;
// Flags layout.
#define FLAGS_BIT_FIELDS(V, _) \
V(IsPrivateBit, bool, 1, _) \
V(IsWellKnownSymbolBit, bool, 1, _) \
V(IsPublicBit, bool, 1, _) \
V(IsInterestingSymbolBit, bool, 1, _) \
V(IsPrivateFieldBit, bool, 1, _)
DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
#undef FLAGS_BIT_FIELDS
typedef FixedBodyDescriptor<kNameOffset, kSize, kSize> BodyDescriptor;
// No weak fields.
typedef BodyDescriptor BodyDescriptorWeak;
......
......@@ -19,8 +19,17 @@
namespace v8 {
namespace internal {
SMI_ACCESSORS(String, length, kLengthOffset)
SYNCHRONIZED_SMI_ACCESSORS(String, length, kLengthOffset)
INT32_ACCESSORS(String, length, kLengthOffset)
int String::synchronized_length() const {
return base::AsAtomic32::Acquire_Load(
reinterpret_cast<const int32_t*>(FIELD_ADDR(this, kLengthOffset)));
}
void String::synchronized_set_length(int value) {
base::AsAtomic32::Release_Store(
reinterpret_cast<int32_t*>(FIELD_ADDR(this, kLengthOffset)), value);
}
CAST_ACCESSOR(ConsString)
CAST_ACCESSOR(ExternalOneByteString)
......
......@@ -341,8 +341,8 @@ class String : public Name {
inline bool IsFlat();
// Layout description.
static const int kLengthOffset = Name::kSize;
static const int kSize = kLengthOffset + kPointerSize;
static const int kLengthOffset = Name::kHeaderSize;
static const int kHeaderSize = kLengthOffset + kInt32Size;
// Max char codes.
static const int32_t kMaxOneByteCharCode = unibrow::Latin1::kMaxChar;
......@@ -360,7 +360,7 @@ class String : public Name {
// See include/v8.h for the definition.
static const int kMaxLength = v8::String::kMaxLength;
static_assert(kMaxLength <= (Smi::kMaxValue / 2 - kSize),
static_assert(kMaxLength <= (Smi::kMaxValue / 2 - kHeaderSize),
"Unexpected max String length");
// Max length for computing hash. For strings longer than this limit the
......@@ -474,9 +474,6 @@ class SeqString : public String {
public:
DECL_CAST(SeqString)
// Layout description.
static const int kHeaderSize = String::kSize;
// Truncate the string in-place if possible and return the result.
// In case of new_length == 0, the empty string is returned without
// truncating the original string.
......@@ -620,7 +617,7 @@ class ConsString : public String {
DECL_CAST(ConsString)
// Layout description.
static const int kFirstOffset = POINTER_SIZE_ALIGN(String::kSize);
static const int kFirstOffset = String::kHeaderSize;
static const int kSecondOffset = kFirstOffset + kPointerSize;
static const int kSize = kSecondOffset + kPointerSize;
......@@ -659,7 +656,7 @@ class ThinString : public String {
DECL_VERIFIER(ThinString)
// Layout description.
static const int kActualOffset = String::kSize;
static const int kActualOffset = String::kHeaderSize;
static const int kSize = kActualOffset + kPointerSize;
typedef FixedBodyDescriptor<kActualOffset, kSize, kSize> BodyDescriptor;
......@@ -696,7 +693,7 @@ class SlicedString : public String {
DECL_CAST(SlicedString)
// Layout description.
static const int kParentOffset = POINTER_SIZE_ALIGN(String::kSize);
static const int kParentOffset = String::kHeaderSize;
static const int kOffsetOffset = kParentOffset + kPointerSize;
static const int kSize = kOffsetOffset + kPointerSize;
......@@ -729,7 +726,7 @@ class ExternalString : public String {
DECL_CAST(ExternalString)
// Layout description.
static const int kResourceOffset = POINTER_SIZE_ALIGN(String::kSize);
static const int kResourceOffset = String::kHeaderSize;
static const int kUncachedSize = kResourceOffset + kPointerSize;
static const int kResourceDataOffset = kResourceOffset + kPointerSize;
static const int kSize = kResourceDataOffset + kPointerSize;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment