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

[turbofan] Introduce dedicated NewConsString operator.

This is in preparation of adding a dedicated StringLength operator that
loads the string length. This way operations on strings don't sit in the
effect chain anymore until the EffectControlLinearizer, which wires them.

The NewConsString semantics could still be better, i.e. it could try to
figure out the proper map instead of going for the CONS_STRING_TYPE
always. But this change is meant to be just about pushing the logic down
to the EffectControlLinearizer, which we didn't have initially when the
ConsString handling was done.

This also allows us to remove the handling of CONS_STRING_TYPE from the
Deoptimizer, since the escape analysis no longer sees cons strings.

Bug: v8:5269, v8:6936, v8:7109, v8:7137
Change-Id: If6c4a6d7cf63a3a3f7a34a920c8e50a94dfa67fa
Reviewed-on: https://chromium-review.googlesource.com/796413
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49729}
parent c30472b8
......@@ -842,6 +842,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kNewArgumentsElements:
result = LowerNewArgumentsElements(node);
break;
case IrOpcode::kNewConsString:
result = LowerNewConsString(node);
break;
case IrOpcode::kArrayBufferWasNeutered:
result = LowerArrayBufferWasNeutered(node);
break;
......@@ -2493,6 +2496,28 @@ Node* EffectControlLinearizer::LowerNewArgumentsElements(Node* node) {
__ SmiConstant(mapped_count), __ NoContextConstant());
}
Node* EffectControlLinearizer::LowerNewConsString(Node* node) {
Node* length = node->InputAt(0);
Node* first = node->InputAt(1);
Node* second = node->InputAt(2);
// TODO(turbofan): We currently just use the cons_string_map here for
// the sake of simplicity; we could also try to be smarter here and
// use the one_byte_cons_string_map instead when the resulting ConsString
// contains only one byte characters.
Node* result_map = jsgraph()->HeapConstant(factory()->cons_string_map());
// Allocate the resulting ConsString.
Node* result = __ Allocate(NOT_TENURED, __ Int32Constant(ConsString::kSize));
__ StoreField(AccessBuilder::ForMap(), result, result_map);
__ StoreField(AccessBuilder::ForNameHashField(), result,
jsgraph()->Int32Constant(Name::kEmptyHashField));
__ StoreField(AccessBuilder::ForStringLength(), result, length);
__ StoreField(AccessBuilder::ForConsStringFirst(), result, first);
__ StoreField(AccessBuilder::ForConsStringSecond(), result, second);
return result;
}
Node* EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node) {
Node* value = node->InputAt(0);
......
......@@ -105,6 +105,7 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerNewDoubleElements(Node* node);
Node* LowerNewSmiOrObjectElements(Node* node);
Node* LowerNewArgumentsElements(Node* node);
Node* LowerNewConsString(Node* node);
Node* LowerArrayBufferWasNeutered(Node* node);
Node* LowerSameValue(Node* node);
Node* LowerStringToNumber(Node* node);
......
......@@ -698,29 +698,14 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
Revisit(graph()->end());
}
control = graph()->NewNode(common()->IfTrue(), branch);
length = graph()->NewNode(
common()->TypeGuard(type_cache_.kStringLengthType), length, control);
}
// Figure out the map for the resulting ConsString.
// TODO(turbofan): We currently just use the cons_string_map here for
// the sake of simplicity; we could also try to be smarter here and
// use the one_byte_cons_string_map instead when the resulting ConsString
// contains only one byte characters.
Node* value_map = jsgraph()->HeapConstant(factory()->cons_string_map());
// Allocate the resulting ConsString.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(ConsString::kSize, NOT_TENURED, Type::OtherString());
a.Store(AccessBuilder::ForMap(), value_map);
a.Store(AccessBuilder::ForNameHashField(),
jsgraph()->Constant(Name::kEmptyHashField));
a.Store(AccessBuilder::ForStringLength(), length);
a.Store(AccessBuilder::ForConsStringFirst(), first);
a.Store(AccessBuilder::ForConsStringSecond(), second);
// Morph the {node} into a {FinishRegion}.
ReplaceWithValue(node, node, node, control);
a.FinishAndChange(node);
return Changed(node);
Node* value =
graph()->NewNode(simplified()->NewConsString(), length, first, second);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
Node* JSTypedLowering::BuildGetStringLength(Node* value, Node** effect,
......
......@@ -390,6 +390,7 @@
V(NewDoubleElements) \
V(NewSmiOrObjectElements) \
V(NewArgumentsElements) \
V(NewConsString) \
V(ArrayBufferWasNeutered) \
V(EnsureWritableFastElements) \
V(MaybeGrowFastElements) \
......
......@@ -2365,6 +2365,13 @@ class RepresentationSelector {
return VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
}
case IrOpcode::kNewConsString: {
ProcessInput(node, 0, UseInfo::TaggedSigned()); // length
ProcessInput(node, 1, UseInfo::AnyTagged()); // first
ProcessInput(node, 2, UseInfo::AnyTagged()); // second
SetOutput(node, MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual: {
......
......@@ -632,7 +632,8 @@ DeoptimizeReason DeoptimizeReasonOf(const Operator* op) {
V(StringEqual, Operator::kCommutative, 2, 0) \
V(StringLessThan, Operator::kNoProperties, 2, 0) \
V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0) \
V(ToBoolean, Operator::kNoProperties, 1, 0)
V(ToBoolean, Operator::kNoProperties, 1, 0) \
V(NewConsString, Operator::kNoProperties, 3, 0)
#define SPECULATIVE_NUMBER_BINOP_LIST(V) \
SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
......
......@@ -502,6 +502,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
// new-arguments-elements arguments-frame, arguments-length
const Operator* NewArgumentsElements(int mapped_count);
// new-cons-string length, first, second
const Operator* NewConsString();
// array-buffer-was-neutered buffer
const Operator* ArrayBufferWasNeutered();
......
......@@ -2201,6 +2201,10 @@ Type* Typer::Visitor::TypeNewArgumentsElements(Node* node) {
return Type::OtherInternal();
}
Type* Typer::Visitor::TypeNewConsString(Node* node) {
return Type::OtherNonSeqString();
}
Type* Typer::Visitor::TypeArrayBufferWasNeutered(Node* node) {
return Type::Boolean();
}
......
......@@ -1122,6 +1122,12 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
Code::kMaxArguments, zone));
CheckTypeIs(node, Type::OtherInternal());
break;
case IrOpcode::kNewConsString:
CheckValueInputIs(node, 0, TypeCache::Get().kStringLengthType);
CheckValueInputIs(node, 1, Type::String());
CheckValueInputIs(node, 2, Type::String());
CheckTypeIs(node, Type::OtherString());
break;
case IrOpcode::kAllocate:
CheckValueInputIs(node, 0, Type::PlainNumber());
break;
......
......@@ -3502,24 +3502,6 @@ Handle<Object> TranslatedState::MaterializeCapturedObjectAt(
}
return object;
}
case CONS_STRING_TYPE: {
Handle<ConsString> object = Handle<ConsString>::cast(
isolate_->factory()
->NewConsString(isolate_->factory()->undefined_string(),
isolate_->factory()->undefined_string())
.ToHandleChecked());
slot->value_ = object;
Handle<Object> hash = materializer.FieldAt(value_index);
Handle<Object> string_length = materializer.FieldAt(value_index);
Handle<Object> first = materializer.FieldAt(value_index);
Handle<Object> second = materializer.FieldAt(value_index);
object->set_map(*map);
object->set_length(Smi::ToInt(*string_length));
object->set_first(String::cast(*first));
object->set_second(String::cast(*second));
CHECK(hash->IsNumber()); // The {Name::kEmptyHashField} value.
return object;
}
case CONTEXT_EXTENSION_TYPE: {
Handle<ContextExtension> object =
isolate_->factory()->NewContextExtension(
......@@ -3607,6 +3589,7 @@ Handle<Object> TranslatedState::MaterializeCapturedObjectAt(
}
case STRING_TYPE:
case ONE_BYTE_STRING_TYPE:
case CONS_STRING_TYPE:
case CONS_ONE_BYTE_STRING_TYPE:
case SLICED_STRING_TYPE:
case SLICED_ONE_BYTE_STRING_TYPE:
......
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