Commit 14fa66b7 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[turbofan] Add SeqStringCharCodeAt operation.

Add a sequential string type to the compiler, and transform
charCodeAt on SeqString into SeqStringCharCodeAt.

SeqStringCharCodeAt can handle one and two byte strings.

Bug: v8:6391
Change-Id: I2785257522c28f3b268c9833f5313e9630cb982a
Reviewed-on: https://chromium-review.googlesource.com/509573Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45508}
parent 02fee655
......@@ -766,6 +766,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStringCharCodeAt:
result = LowerStringCharCodeAt(node);
break;
case IrOpcode::kSeqStringCharCodeAt:
result = LowerSeqStringCharCodeAt(node);
break;
case IrOpcode::kStringEqual:
result = LowerStringEqual(node);
break;
......@@ -2126,6 +2129,33 @@ Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) {
__ NoContextConstant());
}
Node* EffectControlLinearizer::LowerSeqStringCharCodeAt(Node* node) {
Node* receiver = node->InputAt(0);
Node* position = node->InputAt(1);
auto one_byte_load = __ MakeLabel<1>();
auto done = __ MakeLabel<2>(MachineRepresentation::kTagged);
Node* map = __ LoadField(AccessBuilder::ForMap(), receiver);
Node* instance_type = __ LoadField(AccessBuilder::ForMapInstanceType(), map);
Node* is_one_byte = __ Word32Equal(
__ Word32And(instance_type, __ Int32Constant(kStringEncodingMask)),
__ Int32Constant(kOneByteStringTag));
__ GotoIf(is_one_byte, &one_byte_load);
Node* two_byte_result = __ LoadElement(
AccessBuilder::ForSeqTwoByteStringCharacter(), receiver, position);
__ Goto(&done, two_byte_result);
__ Bind(&one_byte_load);
Node* one_byte_element = __ LoadElement(
AccessBuilder::ForSeqOneByteStringCharacter(), receiver, position);
__ Goto(&done, one_byte_element);
__ Bind(&done);
return done.PhiAt(0);
}
Node* EffectControlLinearizer::LowerStringFromCharCode(Node* node) {
Node* value = node->InputAt(0);
......
......@@ -97,6 +97,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerArrayBufferWasNeutered(Node* node);
Node* LowerStringCharAt(Node* node);
Node* LowerStringCharCodeAt(Node* node);
Node* LowerSeqStringCharCodeAt(Node* node);
Node* LowerStringFromCharCode(Node* node);
Node* LowerStringFromCodePoint(Node* node);
Node* LowerStringIndexOf(Node* node);
......
......@@ -836,6 +836,7 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
case IrOpcode::kPlainPrimitiveToFloat64:
case IrOpcode::kStringCharAt:
case IrOpcode::kStringCharCodeAt:
case IrOpcode::kSeqStringCharCodeAt:
case IrOpcode::kStringIndexOf:
case IrOpcode::kObjectIsDetectableCallable:
case IrOpcode::kObjectIsNaN:
......
......@@ -311,6 +311,7 @@
V(BooleanNot) \
V(StringCharAt) \
V(StringCharCodeAt) \
V(SeqStringCharCodeAt) \
V(StringFromCharCode) \
V(StringFromCodePoint) \
V(StringIndexOf) \
......
......@@ -2333,9 +2333,18 @@ class RepresentationSelector {
return;
}
case IrOpcode::kStringCharCodeAt: {
// TODO(turbofan): Allow builtins to return untagged values.
VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
MachineRepresentation::kTaggedSigned);
Type* string_type = TypeOf(node->InputAt(0));
if (string_type->Is(Type::SeqString())) {
VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) {
NodeProperties::ChangeOp(node, simplified()->SeqStringCharCodeAt());
}
} else {
// TODO(turbofan): Allow builtins to return untagged values.
VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
MachineRepresentation::kTaggedSigned);
}
return;
}
case IrOpcode::kStringFromCharCode: {
......
......@@ -472,6 +472,7 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \
V(StringCharAt, Operator::kNoProperties, 2, 1) \
V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(SeqStringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(StringFromCharCode, Operator::kNoProperties, 1, 0) \
V(StringIndexOf, Operator::kNoProperties, 3, 0) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
......
......@@ -378,6 +378,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringLessThanOrEqual();
const Operator* StringCharAt();
const Operator* StringCharCodeAt();
const Operator* SeqStringCharCodeAt();
const Operator* StringFromCharCode();
const Operator* StringFromCodePoint(UnicodeEncoding encoding);
const Operator* StringIndexOf();
......
......@@ -1771,6 +1771,10 @@ Type* Typer::Visitor::TypeStringCharCodeAt(Node* node) {
return typer_->cache_.kUint16;
}
Type* Typer::Visitor::TypeSeqStringCharCodeAt(Node* node) {
return typer_->cache_.kUint16;
}
Type* Typer::Visitor::TypeStringFromCharCode(Node* node) {
return TypeUnaryOp(node, StringFromCharCodeTyper);
}
......
......@@ -145,8 +145,6 @@ Type::bitset BitsetType::Lub(Type* type) {
Type::bitset BitsetType::Lub(i::Map* map) {
DisallowHeapAllocation no_allocation;
switch (map->instance_type()) {
case STRING_TYPE:
case ONE_BYTE_STRING_TYPE:
case CONS_STRING_TYPE:
case CONS_ONE_BYTE_STRING_TYPE:
case THIN_STRING_TYPE:
......@@ -159,16 +157,20 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case SHORT_EXTERNAL_STRING_TYPE:
case SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE:
case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
return kOtherString;
case INTERNALIZED_STRING_TYPE:
case ONE_BYTE_INTERNALIZED_STRING_TYPE:
return kOtherNonSeqString;
case STRING_TYPE:
case ONE_BYTE_STRING_TYPE:
return kOtherSeqString;
case EXTERNAL_INTERNALIZED_STRING_TYPE:
case EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
return kInternalizedString;
return kInternalizedNonSeqString;
case INTERNALIZED_STRING_TYPE:
case ONE_BYTE_INTERNALIZED_STRING_TYPE:
return kInternalizedSeqString;
case SYMBOL_TYPE:
return kSymbol;
case ODDBALL_TYPE: {
......
......@@ -105,28 +105,30 @@ namespace compiler {
V(OtherNumber, 1u << 4) \
#define PROPER_BITSET_TYPE_LIST(V) \
V(None, 0u) \
V(Negative31, 1u << 5) \
V(Null, 1u << 6) \
V(Undefined, 1u << 7) \
V(Boolean, 1u << 8) \
V(Unsigned30, 1u << 9) \
V(MinusZero, 1u << 10) \
V(NaN, 1u << 11) \
V(Symbol, 1u << 12) \
V(InternalizedString, 1u << 13) \
V(OtherString, 1u << 14) \
V(OtherCallable, 1u << 15) \
V(OtherObject, 1u << 16) \
V(OtherUndetectable, 1u << 17) \
V(CallableProxy, 1u << 18) \
V(OtherProxy, 1u << 19) \
V(Function, 1u << 20) \
V(BoundFunction, 1u << 21) \
V(Hole, 1u << 22) \
V(OtherInternal, 1u << 23) \
V(ExternalPointer, 1u << 24) \
V(Array, 1u << 25) \
V(None, 0u) \
V(Negative31, 1u << 5) \
V(Null, 1u << 6) \
V(Undefined, 1u << 7) \
V(Boolean, 1u << 8) \
V(Unsigned30, 1u << 9) \
V(MinusZero, 1u << 10) \
V(NaN, 1u << 11) \
V(Symbol, 1u << 12) \
V(InternalizedNonSeqString, 1u << 13) \
V(InternalizedSeqString, 1u << 14) \
V(OtherNonSeqString, 1u << 15) \
V(OtherSeqString, 1u << 16) \
V(OtherCallable, 1u << 17) \
V(OtherObject, 1u << 18) \
V(OtherUndetectable, 1u << 19) \
V(CallableProxy, 1u << 20) \
V(OtherProxy, 1u << 21) \
V(Function, 1u << 22) \
V(BoundFunction, 1u << 23) \
V(Hole, 1u << 24) \
V(OtherInternal, 1u << 25) \
V(ExternalPointer, 1u << 26) \
V(Array, 1u << 27) \
\
V(Signed31, kUnsigned30 | kNegative31) \
V(Signed32, kSigned31 | kOtherUnsigned31 | \
......@@ -146,6 +148,12 @@ namespace compiler {
V(OrderedNumber, kPlainNumber | kMinusZero) \
V(MinusZeroOrNaN, kMinusZero | kNaN) \
V(Number, kOrderedNumber | kNaN) \
V(InternalizedString, kInternalizedNonSeqString | \
kInternalizedSeqString) \
V(OtherString, kOtherNonSeqString | kOtherSeqString) \
V(SeqString, kInternalizedSeqString | kOtherSeqString) \
V(NonSeqString, kInternalizedNonSeqString | \
kOtherNonSeqString) \
V(String, kInternalizedString | kOtherString) \
V(UniqueName, kSymbol | kInternalizedString) \
V(Name, kSymbol | kString) \
......
......@@ -952,6 +952,12 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::Unsigned32());
CheckTypeIs(node, Type::UnsignedSmall());
break;
case IrOpcode::kSeqStringCharCodeAt:
// (SeqString, Unsigned32) -> UnsignedSmall
CheckValueInputIs(node, 0, Type::SeqString());
CheckValueInputIs(node, 1, Type::Unsigned32());
CheckTypeIs(node, Type::UnsignedSmall());
break;
case IrOpcode::kStringFromCharCode:
// Number -> String
CheckValueInputIs(node, 0, Type::Number());
......
......@@ -277,6 +277,14 @@ struct Tests {
CHECK(!T.NewConstant(fac->NewNumber(V8_INFINITY))->Is(T.Integral32));
CHECK(T.NewConstant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber));
CHECK(!T.NewConstant(fac->NewNumber(-V8_INFINITY))->Is(T.Integral32));
// Typing of Strings
Handle<String> s1 = fac->NewStringFromAsciiChecked("a");
CHECK(T.NewConstant(s1)->Is(T.InternalizedSeqString));
const uc16 two_byte[1] = {0x2603};
Handle<String> s2 =
fac->NewTwoByteInternalizedString(Vector<const uc16>(two_byte, 1), 1);
CHECK(T.NewConstant(s2)->Is(T.InternalizedSeqString));
}
void Range() {
......@@ -620,9 +628,14 @@ struct Tests {
CheckSub(T.UniqueName, T.Name);
CheckSub(T.String, T.Name);
CheckSub(T.InternalizedSeqString, T.InternalizedString);
CheckSub(T.InternalizedNonSeqString, T.InternalizedString);
CheckSub(T.InternalizedString, T.String);
CheckSub(T.InternalizedString, T.UniqueName);
CheckSub(T.InternalizedString, T.Name);
CheckSub(T.OtherSeqString, T.OtherString);
CheckSub(T.OtherNonSeqString, T.OtherString);
CheckSub(T.OtherString, T.String);
CheckSub(T.Symbol, T.UniqueName);
CheckSub(T.Symbol, T.Name);
CheckUnordered(T.String, T.UniqueName);
......@@ -746,10 +759,15 @@ struct Tests {
CheckOverlap(T.NaN, T.Number);
CheckDisjoint(T.Signed32, T.NaN);
CheckOverlap(T.UniqueName, T.Name);
CheckOverlap(T.InternalizedNonSeqString, T.InternalizedString);
CheckOverlap(T.InternalizedSeqString, T.InternalizedString);
CheckOverlap(T.OtherNonSeqString, T.OtherString);
CheckOverlap(T.OtherSeqString, T.OtherString);
CheckOverlap(T.String, T.Name);
CheckOverlap(T.InternalizedString, T.String);
CheckOverlap(T.InternalizedString, T.UniqueName);
CheckOverlap(T.InternalizedString, T.Name);
CheckOverlap(T.OtherString, T.String);
CheckOverlap(T.Symbol, T.UniqueName);
CheckOverlap(T.Symbol, T.Name);
CheckOverlap(T.String, T.UniqueName);
......
......@@ -141,7 +141,6 @@ function TestStringType(generator, sixteen) {
assertEquals(116, g().charCodeAt(3.14159), 26 + t);
}
TestStringType(Cons, false);
TestStringType(Deep, false);
TestStringType(Slice, false);
......@@ -155,6 +154,15 @@ TestStringType(Slice16End, true);
TestStringType(Flat16, true);
TestStringType(NotAString16, true);
function Flat16Optimized() {
var str = Flat16();
return str.charCodeAt(2);
}
assertEquals(0x1234, Flat16Optimized());
assertEquals(0x1234, Flat16Optimized());
%OptimizeFunctionOnNextCall(Flat16Optimized);
assertEquals(0x1234, Flat16Optimized());
function ConsNotSmiIndex() {
var str = Cons();
......
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