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, ...@@ -766,6 +766,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStringCharCodeAt: case IrOpcode::kStringCharCodeAt:
result = LowerStringCharCodeAt(node); result = LowerStringCharCodeAt(node);
break; break;
case IrOpcode::kSeqStringCharCodeAt:
result = LowerSeqStringCharCodeAt(node);
break;
case IrOpcode::kStringEqual: case IrOpcode::kStringEqual:
result = LowerStringEqual(node); result = LowerStringEqual(node);
break; break;
...@@ -2126,6 +2129,33 @@ Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) { ...@@ -2126,6 +2129,33 @@ Node* EffectControlLinearizer::LowerStringCharCodeAt(Node* node) {
__ NoContextConstant()); __ 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* EffectControlLinearizer::LowerStringFromCharCode(Node* node) {
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
......
...@@ -97,6 +97,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -97,6 +97,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerArrayBufferWasNeutered(Node* node); Node* LowerArrayBufferWasNeutered(Node* node);
Node* LowerStringCharAt(Node* node); Node* LowerStringCharAt(Node* node);
Node* LowerStringCharCodeAt(Node* node); Node* LowerStringCharCodeAt(Node* node);
Node* LowerSeqStringCharCodeAt(Node* node);
Node* LowerStringFromCharCode(Node* node); Node* LowerStringFromCharCode(Node* node);
Node* LowerStringFromCodePoint(Node* node); Node* LowerStringFromCodePoint(Node* node);
Node* LowerStringIndexOf(Node* node); Node* LowerStringIndexOf(Node* node);
......
...@@ -836,6 +836,7 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, ...@@ -836,6 +836,7 @@ bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
case IrOpcode::kPlainPrimitiveToFloat64: case IrOpcode::kPlainPrimitiveToFloat64:
case IrOpcode::kStringCharAt: case IrOpcode::kStringCharAt:
case IrOpcode::kStringCharCodeAt: case IrOpcode::kStringCharCodeAt:
case IrOpcode::kSeqStringCharCodeAt:
case IrOpcode::kStringIndexOf: case IrOpcode::kStringIndexOf:
case IrOpcode::kObjectIsDetectableCallable: case IrOpcode::kObjectIsDetectableCallable:
case IrOpcode::kObjectIsNaN: case IrOpcode::kObjectIsNaN:
......
...@@ -311,6 +311,7 @@ ...@@ -311,6 +311,7 @@
V(BooleanNot) \ V(BooleanNot) \
V(StringCharAt) \ V(StringCharAt) \
V(StringCharCodeAt) \ V(StringCharCodeAt) \
V(SeqStringCharCodeAt) \
V(StringFromCharCode) \ V(StringFromCharCode) \
V(StringFromCodePoint) \ V(StringFromCodePoint) \
V(StringIndexOf) \ V(StringIndexOf) \
......
...@@ -2333,9 +2333,18 @@ class RepresentationSelector { ...@@ -2333,9 +2333,18 @@ class RepresentationSelector {
return; return;
} }
case IrOpcode::kStringCharCodeAt: { case IrOpcode::kStringCharCodeAt: {
// TODO(turbofan): Allow builtins to return untagged values. Type* string_type = TypeOf(node->InputAt(0));
VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(), if (string_type->Is(Type::SeqString())) {
MachineRepresentation::kTaggedSigned); 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; return;
} }
case IrOpcode::kStringFromCharCode: { case IrOpcode::kStringFromCharCode: {
......
...@@ -472,6 +472,7 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) { ...@@ -472,6 +472,7 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \ V(NumberSilenceNaN, Operator::kNoProperties, 1, 0) \
V(StringCharAt, Operator::kNoProperties, 2, 1) \ V(StringCharAt, Operator::kNoProperties, 2, 1) \
V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \ V(StringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(SeqStringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(StringFromCharCode, Operator::kNoProperties, 1, 0) \ V(StringFromCharCode, Operator::kNoProperties, 1, 0) \
V(StringIndexOf, Operator::kNoProperties, 3, 0) \ V(StringIndexOf, Operator::kNoProperties, 3, 0) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \ V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
......
...@@ -378,6 +378,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -378,6 +378,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringLessThanOrEqual(); const Operator* StringLessThanOrEqual();
const Operator* StringCharAt(); const Operator* StringCharAt();
const Operator* StringCharCodeAt(); const Operator* StringCharCodeAt();
const Operator* SeqStringCharCodeAt();
const Operator* StringFromCharCode(); const Operator* StringFromCharCode();
const Operator* StringFromCodePoint(UnicodeEncoding encoding); const Operator* StringFromCodePoint(UnicodeEncoding encoding);
const Operator* StringIndexOf(); const Operator* StringIndexOf();
......
...@@ -1771,6 +1771,10 @@ Type* Typer::Visitor::TypeStringCharCodeAt(Node* node) { ...@@ -1771,6 +1771,10 @@ Type* Typer::Visitor::TypeStringCharCodeAt(Node* node) {
return typer_->cache_.kUint16; return typer_->cache_.kUint16;
} }
Type* Typer::Visitor::TypeSeqStringCharCodeAt(Node* node) {
return typer_->cache_.kUint16;
}
Type* Typer::Visitor::TypeStringFromCharCode(Node* node) { Type* Typer::Visitor::TypeStringFromCharCode(Node* node) {
return TypeUnaryOp(node, StringFromCharCodeTyper); return TypeUnaryOp(node, StringFromCharCodeTyper);
} }
......
...@@ -145,8 +145,6 @@ Type::bitset BitsetType::Lub(Type* type) { ...@@ -145,8 +145,6 @@ Type::bitset BitsetType::Lub(Type* type) {
Type::bitset BitsetType::Lub(i::Map* map) { Type::bitset BitsetType::Lub(i::Map* map) {
DisallowHeapAllocation no_allocation; DisallowHeapAllocation no_allocation;
switch (map->instance_type()) { switch (map->instance_type()) {
case STRING_TYPE:
case ONE_BYTE_STRING_TYPE:
case CONS_STRING_TYPE: case CONS_STRING_TYPE:
case CONS_ONE_BYTE_STRING_TYPE: case CONS_ONE_BYTE_STRING_TYPE:
case THIN_STRING_TYPE: case THIN_STRING_TYPE:
...@@ -159,16 +157,20 @@ Type::bitset BitsetType::Lub(i::Map* map) { ...@@ -159,16 +157,20 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case SHORT_EXTERNAL_STRING_TYPE: case SHORT_EXTERNAL_STRING_TYPE:
case SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE: case SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE:
case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE: case SHORT_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
return kOtherString; return kOtherNonSeqString;
case INTERNALIZED_STRING_TYPE: case STRING_TYPE:
case ONE_BYTE_INTERNALIZED_STRING_TYPE: case ONE_BYTE_STRING_TYPE:
return kOtherSeqString;
case EXTERNAL_INTERNALIZED_STRING_TYPE: case EXTERNAL_INTERNALIZED_STRING_TYPE:
case EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE: case EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE: case EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE: case SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE: case SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE:
case SHORT_EXTERNAL_INTERNALIZED_STRING_WITH_ONE_BYTE_DATA_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: case SYMBOL_TYPE:
return kSymbol; return kSymbol;
case ODDBALL_TYPE: { case ODDBALL_TYPE: {
......
...@@ -105,28 +105,30 @@ namespace compiler { ...@@ -105,28 +105,30 @@ namespace compiler {
V(OtherNumber, 1u << 4) \ V(OtherNumber, 1u << 4) \
#define PROPER_BITSET_TYPE_LIST(V) \ #define PROPER_BITSET_TYPE_LIST(V) \
V(None, 0u) \ V(None, 0u) \
V(Negative31, 1u << 5) \ V(Negative31, 1u << 5) \
V(Null, 1u << 6) \ V(Null, 1u << 6) \
V(Undefined, 1u << 7) \ V(Undefined, 1u << 7) \
V(Boolean, 1u << 8) \ V(Boolean, 1u << 8) \
V(Unsigned30, 1u << 9) \ V(Unsigned30, 1u << 9) \
V(MinusZero, 1u << 10) \ V(MinusZero, 1u << 10) \
V(NaN, 1u << 11) \ V(NaN, 1u << 11) \
V(Symbol, 1u << 12) \ V(Symbol, 1u << 12) \
V(InternalizedString, 1u << 13) \ V(InternalizedNonSeqString, 1u << 13) \
V(OtherString, 1u << 14) \ V(InternalizedSeqString, 1u << 14) \
V(OtherCallable, 1u << 15) \ V(OtherNonSeqString, 1u << 15) \
V(OtherObject, 1u << 16) \ V(OtherSeqString, 1u << 16) \
V(OtherUndetectable, 1u << 17) \ V(OtherCallable, 1u << 17) \
V(CallableProxy, 1u << 18) \ V(OtherObject, 1u << 18) \
V(OtherProxy, 1u << 19) \ V(OtherUndetectable, 1u << 19) \
V(Function, 1u << 20) \ V(CallableProxy, 1u << 20) \
V(BoundFunction, 1u << 21) \ V(OtherProxy, 1u << 21) \
V(Hole, 1u << 22) \ V(Function, 1u << 22) \
V(OtherInternal, 1u << 23) \ V(BoundFunction, 1u << 23) \
V(ExternalPointer, 1u << 24) \ V(Hole, 1u << 24) \
V(Array, 1u << 25) \ V(OtherInternal, 1u << 25) \
V(ExternalPointer, 1u << 26) \
V(Array, 1u << 27) \
\ \
V(Signed31, kUnsigned30 | kNegative31) \ V(Signed31, kUnsigned30 | kNegative31) \
V(Signed32, kSigned31 | kOtherUnsigned31 | \ V(Signed32, kSigned31 | kOtherUnsigned31 | \
...@@ -146,6 +148,12 @@ namespace compiler { ...@@ -146,6 +148,12 @@ namespace compiler {
V(OrderedNumber, kPlainNumber | kMinusZero) \ V(OrderedNumber, kPlainNumber | kMinusZero) \
V(MinusZeroOrNaN, kMinusZero | kNaN) \ V(MinusZeroOrNaN, kMinusZero | kNaN) \
V(Number, kOrderedNumber | 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(String, kInternalizedString | kOtherString) \
V(UniqueName, kSymbol | kInternalizedString) \ V(UniqueName, kSymbol | kInternalizedString) \
V(Name, kSymbol | kString) \ V(Name, kSymbol | kString) \
......
...@@ -952,6 +952,12 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -952,6 +952,12 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 1, Type::Unsigned32()); CheckValueInputIs(node, 1, Type::Unsigned32());
CheckTypeIs(node, Type::UnsignedSmall()); CheckTypeIs(node, Type::UnsignedSmall());
break; 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: case IrOpcode::kStringFromCharCode:
// Number -> String // Number -> String
CheckValueInputIs(node, 0, Type::Number()); CheckValueInputIs(node, 0, Type::Number());
......
...@@ -277,6 +277,14 @@ struct Tests { ...@@ -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.Integral32));
CHECK(T.NewConstant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber)); CHECK(T.NewConstant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber));
CHECK(!T.NewConstant(fac->NewNumber(-V8_INFINITY))->Is(T.Integral32)); 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() { void Range() {
...@@ -620,9 +628,14 @@ struct Tests { ...@@ -620,9 +628,14 @@ struct Tests {
CheckSub(T.UniqueName, T.Name); CheckSub(T.UniqueName, T.Name);
CheckSub(T.String, 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.String);
CheckSub(T.InternalizedString, T.UniqueName); CheckSub(T.InternalizedString, T.UniqueName);
CheckSub(T.InternalizedString, T.Name); 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.UniqueName);
CheckSub(T.Symbol, T.Name); CheckSub(T.Symbol, T.Name);
CheckUnordered(T.String, T.UniqueName); CheckUnordered(T.String, T.UniqueName);
...@@ -746,10 +759,15 @@ struct Tests { ...@@ -746,10 +759,15 @@ struct Tests {
CheckOverlap(T.NaN, T.Number); CheckOverlap(T.NaN, T.Number);
CheckDisjoint(T.Signed32, T.NaN); CheckDisjoint(T.Signed32, T.NaN);
CheckOverlap(T.UniqueName, T.Name); 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.String, T.Name);
CheckOverlap(T.InternalizedString, T.String); CheckOverlap(T.InternalizedString, T.String);
CheckOverlap(T.InternalizedString, T.UniqueName); CheckOverlap(T.InternalizedString, T.UniqueName);
CheckOverlap(T.InternalizedString, T.Name); CheckOverlap(T.InternalizedString, T.Name);
CheckOverlap(T.OtherString, T.String);
CheckOverlap(T.Symbol, T.UniqueName); CheckOverlap(T.Symbol, T.UniqueName);
CheckOverlap(T.Symbol, T.Name); CheckOverlap(T.Symbol, T.Name);
CheckOverlap(T.String, T.UniqueName); CheckOverlap(T.String, T.UniqueName);
......
...@@ -141,7 +141,6 @@ function TestStringType(generator, sixteen) { ...@@ -141,7 +141,6 @@ function TestStringType(generator, sixteen) {
assertEquals(116, g().charCodeAt(3.14159), 26 + t); assertEquals(116, g().charCodeAt(3.14159), 26 + t);
} }
TestStringType(Cons, false); TestStringType(Cons, false);
TestStringType(Deep, false); TestStringType(Deep, false);
TestStringType(Slice, false); TestStringType(Slice, false);
...@@ -155,6 +154,15 @@ TestStringType(Slice16End, true); ...@@ -155,6 +154,15 @@ TestStringType(Slice16End, true);
TestStringType(Flat16, true); TestStringType(Flat16, true);
TestStringType(NotAString16, 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() { function ConsNotSmiIndex() {
var str = Cons(); 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