Commit 53e00e39 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

Reland "[turbofan] Move String.* functions to JSCallReducer"

This is a reland of 3ff4b447.

Original version did not handle V8_INTL_SUPPORT.

Original change's description:
> [turbofan] Move String.* functions to JSCallReducer
>
> Bug: v8:7250, v8:7340
> Change-Id: Ibb8d5badf89c66bd9bcb6bb390256ae81d0e899c
> Reviewed-on: https://chromium-review.googlesource.com/913208
> Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#51505}

Bug: v8:7250, v8:7340
Change-Id: Id908cbcfaa9e9cf5459d6d3289e6ec00e387d287
Reviewed-on: https://chromium-review.googlesource.com/934268Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51514}
parent 481c21e0
......@@ -872,30 +872,6 @@ Reduction JSBuiltinReducer::ReduceArrayIsArray(Node* node) {
return Replace(value);
}
namespace {
bool HasInstanceTypeWitness(Node* receiver, Node* effect,
InstanceType instance_type) {
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
switch (result) {
case NodeProperties::kUnreliableReceiverMaps:
case NodeProperties::kReliableReceiverMaps:
DCHECK_NE(0, receiver_maps.size());
for (size_t i = 0; i < receiver_maps.size(); ++i) {
if (receiver_maps[i]->instance_type() != instance_type) return false;
}
return true;
case NodeProperties::kNoReceiverMaps:
return false;
}
UNREACHABLE();
}
} // namespace
Reduction JSBuiltinReducer::ReduceCollectionIterator(
Node* node, InstanceType collection_instance_type,
int collection_iterator_map_index) {
......@@ -903,7 +879,8 @@ Reduction JSBuiltinReducer::ReduceCollectionIterator(
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (HasInstanceTypeWitness(receiver, effect, collection_instance_type)) {
if (NodeProperties::HasInstanceTypeWitness(receiver, effect,
collection_instance_type)) {
// Figure out the proper collection iterator map.
Handle<Map> collection_iterator_map(
Map::cast(native_context()->get(collection_iterator_map_index)),
......@@ -938,7 +915,8 @@ Reduction JSBuiltinReducer::ReduceCollectionSize(
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (HasInstanceTypeWitness(receiver, effect, collection_instance_type)) {
if (NodeProperties::HasInstanceTypeWitness(receiver, effect,
collection_instance_type)) {
Node* table = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSCollectionTable()),
receiver, effect, control);
......@@ -1244,7 +1222,7 @@ Reduction JSBuiltinReducer::ReduceDateGetTime(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) {
if (NodeProperties::HasInstanceTypeWitness(receiver, effect, JS_DATE_TYPE)) {
Node* value = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSDateValue()), receiver,
effect, control);
......@@ -1290,7 +1268,8 @@ Reduction JSBuiltinReducer::ReduceMapGet(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
Node* key = NodeProperties::GetValueInput(node, 2);
if (!HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE)) return NoChange();
if (!NodeProperties::HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE))
return NoChange();
Node* table = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
......@@ -1333,7 +1312,8 @@ Reduction JSBuiltinReducer::ReduceMapHas(Node* node) {
Node* control = NodeProperties::GetControlInput(node);
Node* key = NodeProperties::GetValueInput(node, 2);
if (!HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE)) return NoChange();
if (!NodeProperties::HasInstanceTypeWitness(receiver, effect, JS_MAP_TYPE))
return NoChange();
Node* table = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSCollectionTable()), receiver,
......@@ -1503,18 +1483,6 @@ Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) {
return Replace(value);
}
// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
Reduction JSBuiltinReducer::ReduceStringFromCharCode(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// String.fromCharCode(a:plain-primitive) -> StringFromCharCode(a)
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
return Replace(value);
}
return NoChange();
}
namespace {
Node* GetStringWitness(Node* node) {
......@@ -1573,101 +1541,6 @@ Reduction JSBuiltinReducer::ReduceStringConcat(Node* node) {
return NoChange();
}
Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) {
if (Node* receiver = GetStringWitness(node)) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* map = jsgraph()->HeapConstant(
handle(native_context()->string_iterator_map(), isolate()));
// Allocate new iterator and attach the iterator to this string.
AllocationBuilder a(jsgraph(), effect, control);
a.Allocate(JSStringIterator::kSize, NOT_TENURED, Type::OtherObject());
a.Store(AccessBuilder::ForMap(), map);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSStringIteratorString(), receiver);
a.Store(AccessBuilder::ForJSStringIteratorIndex(),
jsgraph()->SmiConstant(0));
Node* value = effect = a.Finish();
// Replace it.
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
return NoChange();
}
Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
if (HasInstanceTypeWitness(receiver, effect, JS_STRING_ITERATOR_TYPE)) {
Node* string = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
receiver, effect, control);
Node* index = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
receiver, effect, control);
Node* length = graph()->NewNode(simplified()->StringLength(), string);
// branch0: if (index < length)
Node* check0 =
graph()->NewNode(simplified()->NumberLessThan(), index, length);
Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
Node* etrue0 = effect;
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* done_true;
Node* vtrue0;
{
done_true = jsgraph()->FalseConstant();
Node* codepoint = etrue0 = graph()->NewNode(
simplified()->StringCodePointAt(UnicodeEncoding::UTF16), string,
index, etrue0, if_true0);
vtrue0 = graph()->NewNode(
simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), codepoint);
// Update iterator.[[NextIndex]]
Node* char_length =
graph()->NewNode(simplified()->StringLength(), vtrue0);
index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
etrue0 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
receiver, index, etrue0, if_true0);
}
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* done_false;
Node* vfalse0;
{
vfalse0 = jsgraph()->UndefinedConstant();
done_false = jsgraph()->TrueConstant();
}
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue0, vfalse0, control);
Node* done =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
done_true, done_false, control);
value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
value, done, context, effect);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
return NoChange();
}
// ES section #sec-string.prototype.slice
Reduction JSBuiltinReducer::ReduceStringSlice(Node* node) {
if (Node* receiver = GetStringWitness(node)) {
......@@ -1724,30 +1597,6 @@ Reduction JSBuiltinReducer::ReduceStringSlice(Node* node) {
return NoChange();
}
Reduction JSBuiltinReducer::ReduceStringToLowerCaseIntl(Node* node) {
if (Node* receiver = GetStringWitness(node)) {
RelaxEffectsAndControls(node);
node->ReplaceInput(0, receiver);
node->TrimInputCount(1);
NodeProperties::ChangeOp(node, simplified()->StringToLowerCaseIntl());
NodeProperties::SetType(node, Type::String());
return Changed(node);
}
return NoChange();
}
Reduction JSBuiltinReducer::ReduceStringToUpperCaseIntl(Node* node) {
if (Node* receiver = GetStringWitness(node)) {
RelaxEffectsAndControls(node);
node->ReplaceInput(0, receiver);
node->TrimInputCount(1);
NodeProperties::ChangeOp(node, simplified()->StringToUpperCaseIntl());
NodeProperties::SetType(node, Type::String());
return Changed(node);
}
return NoChange();
}
Reduction JSBuiltinReducer::ReduceArrayBufferIsView(Node* node) {
Node* value = node->op()->ValueInputCount() >= 3
? NodeProperties::GetValueInput(node, 2)
......@@ -1764,7 +1613,7 @@ Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (HasInstanceTypeWitness(receiver, effect, instance_type)) {
if (NodeProperties::HasInstanceTypeWitness(receiver, effect, instance_type)) {
// Load the {receiver}s field.
Node* value = effect = graph()->NewNode(simplified()->LoadField(access),
receiver, effect, control);
......@@ -1875,21 +1724,10 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceCollectionIteratorNext(
node, OrderedHashSet::kEntrySize, factory()->empty_ordered_hash_set(),
FIRST_SET_ITERATOR_TYPE, LAST_SET_ITERATOR_TYPE);
case kStringFromCharCode:
reduction = ReduceStringFromCharCode(node);
break;
case kStringConcat:
return ReduceStringConcat(node);
case kStringIterator:
return ReduceStringIterator(node);
case kStringIteratorNext:
return ReduceStringIteratorNext(node);
case kStringSlice:
return ReduceStringSlice(node);
case kStringToLowerCaseIntl:
return ReduceStringToLowerCaseIntl(node);
case kStringToUpperCaseIntl:
return ReduceStringToUpperCaseIntl(node);
case kArrayBufferIsView:
return ReduceArrayBufferIsView(node);
case kDataViewByteLength:
......
......@@ -75,13 +75,8 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
Reduction ReduceNumberIsSafeInteger(Node* node);
Reduction ReduceNumberParseInt(Node* node);
Reduction ReduceObjectCreate(Node* node);
Reduction ReduceStringConcat(Node* node);
Reduction ReduceStringFromCharCode(Node* node);
Reduction ReduceStringIterator(Node* node);
Reduction ReduceStringIteratorNext(Node* node);
Reduction ReduceStringSlice(Node* node);
Reduction ReduceStringToLowerCaseIntl(Node* node);
Reduction ReduceStringToUpperCaseIntl(Node* node);
Reduction ReduceStringConcat(Node* node);
Reduction ReduceArrayBufferIsView(Node* node);
Reduction ReduceArrayBufferViewAccessor(Node* node,
InstanceType instance_type,
......
......@@ -3325,6 +3325,18 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
case Builtins::kStringPrototypeCodePointAt:
return ReduceStringPrototypeStringAt(
simplified()->StringCodePointAt(UnicodeEncoding::UTF32), node);
#ifdef V8_INTL_SUPPORT
case Builtins::kStringPrototypeToLowerCaseIntl:
return ReduceStringPrototypeToLowerCaseIntl(node);
case Builtins::kStringPrototypeToUpperCaseIntl:
return ReduceStringPrototypeToUpperCaseIntl(node);
#endif // V8_INTL_SUPPORT
case Builtins::kStringFromCharCode:
return ReduceStringFromCharCode(node);
case Builtins::kStringPrototypeIterator:
return ReduceStringPrototypeIterator(node);
case Builtins::kStringIteratorPrototypeNext:
return ReduceStringIteratorPrototypeNext(node);
case Builtins::kAsyncFunctionPromiseCreate:
return ReduceAsyncFunctionPromiseCreate(node);
case Builtins::kAsyncFunctionPromiseRelease:
......@@ -3598,46 +3610,6 @@ Reduction JSCallReducer::ReduceJSConstruct(Node* node) {
return NoChange();
}
// ES6 String.prototype.indexOf(searchString [, position])
// #sec-string.prototype.indexof
Reduction JSCallReducer::ReduceStringPrototypeIndexOf(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (node->op()->ValueInputCount() >= 3) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* new_receiver = effect = graph()->NewNode(
simplified()->CheckString(p.feedback()), receiver, effect, control);
Node* search_string = NodeProperties::GetValueInput(node, 2);
Node* new_search_string = effect =
graph()->NewNode(simplified()->CheckString(p.feedback()), search_string,
effect, control);
Node* new_position = jsgraph()->ZeroConstant();
if (node->op()->ValueInputCount() >= 4) {
Node* position = NodeProperties::GetValueInput(node, 3);
new_position = effect = graph()->NewNode(
simplified()->CheckSmi(p.feedback()), position, effect, control);
}
NodeProperties::ReplaceEffectInput(node, effect);
RelaxEffectsAndControls(node);
node->ReplaceInput(0, new_receiver);
node->ReplaceInput(1, new_search_string);
node->ReplaceInput(2, new_position);
node->TrimInputCount(3);
NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
return Changed(node);
}
return NoChange();
}
Reduction JSCallReducer::ReduceJSConstructWithArrayLike(Node* node) {
DCHECK_EQ(IrOpcode::kJSConstructWithArrayLike, node->opcode());
CallFrequency frequency = CallFrequencyOf(node->op());
......@@ -4128,6 +4100,46 @@ Reduction JSCallReducer::ReduceArrayPrototypeShift(Node* node) {
return Replace(value);
}
// ES6 String.prototype.indexOf(searchString [, position])
// #sec-string.prototype.indexof
Reduction JSCallReducer::ReduceStringPrototypeIndexOf(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
if (node->op()->ValueInputCount() >= 3) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* new_receiver = effect = graph()->NewNode(
simplified()->CheckString(p.feedback()), receiver, effect, control);
Node* search_string = NodeProperties::GetValueInput(node, 2);
Node* new_search_string = effect =
graph()->NewNode(simplified()->CheckString(p.feedback()), search_string,
effect, control);
Node* new_position = jsgraph()->ZeroConstant();
if (node->op()->ValueInputCount() >= 4) {
Node* position = NodeProperties::GetValueInput(node, 3);
new_position = effect = graph()->NewNode(
simplified()->CheckSmi(p.feedback()), position, effect, control);
}
NodeProperties::ReplaceEffectInput(node, effect);
RelaxEffectsAndControls(node);
node->ReplaceInput(0, new_receiver);
node->ReplaceInput(1, new_search_string);
node->ReplaceInput(2, new_position);
node->TrimInputCount(3);
NodeProperties::ChangeOp(node, simplified()->StringIndexOf());
return Changed(node);
}
return NoChange();
}
// ES6 section 21.1.3.1 String.prototype.charAt ( pos )
// and
// ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos )
......@@ -4173,6 +4185,163 @@ Reduction JSCallReducer::ReduceStringPrototypeStringAt(
return Replace(value);
}
#ifdef V8_INTL_SUPPORT
Reduction JSCallReducer::ReduceStringPrototypeToLowerCaseIntl(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* receiver = effect =
graph()->NewNode(simplified()->CheckString(p.feedback()),
NodeProperties::GetValueInput(node, 1), effect, control);
NodeProperties::ReplaceEffectInput(node, effect);
RelaxEffectsAndControls(node);
node->ReplaceInput(0, receiver);
node->TrimInputCount(1);
NodeProperties::ChangeOp(node, simplified()->StringToLowerCaseIntl());
NodeProperties::SetType(node, Type::String());
return Changed(node);
}
Reduction JSCallReducer::ReduceStringPrototypeToUpperCaseIntl(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* receiver = effect =
graph()->NewNode(simplified()->CheckString(p.feedback()),
NodeProperties::GetValueInput(node, 1), effect, control);
NodeProperties::ReplaceEffectInput(node, effect);
RelaxEffectsAndControls(node);
node->ReplaceInput(0, receiver);
node->TrimInputCount(1);
NodeProperties::ChangeOp(node, simplified()->StringToUpperCaseIntl());
NodeProperties::SetType(node, Type::String());
return Changed(node);
}
#endif // V8_INTL_SUPPORT
// ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits )
Reduction JSCallReducer::ReduceStringFromCharCode(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
if (node->op()->ValueInputCount() == 3) {
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* input = NodeProperties::GetValueInput(node, 2);
input = effect = graph()->NewNode(
simplified()->SpeculativeToNumber(NumberOperationHint::kNumberOrOddball,
p.feedback()),
input, effect, control);
Node* value = graph()->NewNode(simplified()->StringFromCharCode(), input);
ReplaceWithValue(node, value, effect);
return Replace(value);
}
return NoChange();
}
Reduction JSCallReducer::ReduceStringPrototypeIterator(Node* node) {
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* receiver = effect =
graph()->NewNode(simplified()->CheckString(p.feedback()),
NodeProperties::GetValueInput(node, 1), effect, control);
Node* iterator = effect =
graph()->NewNode(javascript()->CreateStringIterator(), receiver,
jsgraph()->NoContextConstant(), effect);
ReplaceWithValue(node, iterator, effect, control);
return Replace(iterator);
}
Reduction JSCallReducer::ReduceStringIteratorPrototypeNext(Node* node) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
if (NodeProperties::HasInstanceTypeWitness(receiver, effect,
JS_STRING_ITERATOR_TYPE)) {
Node* string = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSStringIteratorString()),
receiver, effect, control);
Node* index = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSStringIteratorIndex()),
receiver, effect, control);
Node* length = graph()->NewNode(simplified()->StringLength(), string);
// branch0: if (index < length)
Node* check0 =
graph()->NewNode(simplified()->NumberLessThan(), index, length);
Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
Node* etrue0 = effect;
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* done_true;
Node* vtrue0;
{
done_true = jsgraph()->FalseConstant();
Node* codepoint = etrue0 = graph()->NewNode(
simplified()->StringCodePointAt(UnicodeEncoding::UTF16), string,
index, etrue0, if_true0);
vtrue0 = graph()->NewNode(
simplified()->StringFromCodePoint(UnicodeEncoding::UTF16), codepoint);
// Update iterator.[[NextIndex]]
Node* char_length =
graph()->NewNode(simplified()->StringLength(), vtrue0);
index = graph()->NewNode(simplified()->NumberAdd(), index, char_length);
etrue0 = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForJSStringIteratorIndex()),
receiver, index, etrue0, if_true0);
}
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* done_false;
Node* vfalse0;
{
vfalse0 = jsgraph()->UndefinedConstant();
done_false = jsgraph()->TrueConstant();
}
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, effect, control);
Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
vtrue0, vfalse0, control);
Node* done =
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
done_true, done_false, control);
value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
value, done, context, effect);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
return NoChange();
}
Reduction JSCallReducer::ReduceAsyncFunctionPromiseCreate(Node* node) {
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
Node* context = NodeProperties::GetContextInput(node);
......
......@@ -100,6 +100,16 @@ class V8_EXPORT_PRIVATE JSCallReducer final : public AdvancedReducer {
Reduction ReduceStringPrototypeIndexOf(Node* node);
Reduction ReduceStringPrototypeStringAt(
const Operator* string_access_operator, Node* node);
#ifdef V8_INTL_SUPPORT
Reduction ReduceStringPrototypeToLowerCaseIntl(Node* node);
Reduction ReduceStringPrototypeToUpperCaseIntl(Node* node);
#endif // V8_INTL_SUPPORT
Reduction ReduceStringFromCharCode(Node* node);
Reduction ReduceStringPrototypeIterator(Node* node);
Reduction ReduceStringIteratorPrototypeNext(Node* node);
Reduction ReduceAsyncFunctionPromiseCreate(Node* node);
Reduction ReduceAsyncFunctionPromiseRelease(Node* node);
Reduction ReducePromiseCapabilityDefaultReject(Node* node);
......
......@@ -143,6 +143,8 @@ Reduction JSCreateLowering::Reduce(Node* node) {
return ReduceJSCreateClosure(node);
case IrOpcode::kJSCreateIterResultObject:
return ReduceJSCreateIterResultObject(node);
case IrOpcode::kJSCreateStringIterator:
return ReduceJSCreateStringIterator(node);
case IrOpcode::kJSCreateKeyValueArray:
return ReduceJSCreateKeyValueArray(node);
case IrOpcode::kJSCreatePromise:
......@@ -982,6 +984,28 @@ Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
return Changed(node);
}
Reduction JSCreateLowering::ReduceJSCreateStringIterator(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateStringIterator, node->opcode());
Node* string = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* map = jsgraph()->HeapConstant(
handle(native_context()->string_iterator_map(), isolate()));
// Allocate new iterator and attach the iterator to this string.
AllocationBuilder a(jsgraph(), effect, graph()->start());
a.Allocate(JSStringIterator::kSize, NOT_TENURED, Type::OtherObject());
a.Store(AccessBuilder::ForMap(), map);
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSObjectElements(),
jsgraph()->EmptyFixedArrayConstant());
a.Store(AccessBuilder::ForJSStringIteratorString(), string);
a.Store(AccessBuilder::ForJSStringIteratorIndex(), jsgraph()->SmiConstant(0));
STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
a.FinishAndChange(node);
return Changed(node);
}
Reduction JSCreateLowering::ReduceJSCreateKeyValueArray(Node* node) {
DCHECK_EQ(IrOpcode::kJSCreateKeyValueArray, node->opcode());
Node* key = NodeProperties::GetValueInput(node, 0);
......
......@@ -53,6 +53,7 @@ class V8_EXPORT_PRIVATE JSCreateLowering final
Reduction ReduceJSCreateBoundFunction(Node* node);
Reduction ReduceJSCreateClosure(Node* node);
Reduction ReduceJSCreateIterResultObject(Node* node);
Reduction ReduceJSCreateStringIterator(Node* node);
Reduction ReduceJSCreateKeyValueArray(Node* node);
Reduction ReduceJSCreatePromise(Node* node);
Reduction ReduceJSCreateLiteralArrayOrObject(Node* node);
......
......@@ -418,6 +418,10 @@ void JSGenericLowering::LowerJSCreateIterResultObject(Node* node) {
UNREACHABLE(); // Eliminated in typed lowering.
}
void JSGenericLowering::LowerJSCreateStringIterator(Node* node) {
UNREACHABLE(); // Eliminated in typed lowering.
}
void JSGenericLowering::LowerJSCreateKeyValueArray(Node* node) {
UNREACHABLE(); // Eliminated in typed lowering.
}
......
......@@ -569,6 +569,7 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
V(ToString, Operator::kNoProperties, 1, 1) \
V(Create, Operator::kNoProperties, 2, 1) \
V(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
V(CreateStringIterator, Operator::kEliminatable, 1, 1) \
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
V(CreatePromise, Operator::kEliminatable, 0, 1) \
V(HasProperty, Operator::kNoProperties, 2, 1) \
......
......@@ -658,6 +658,7 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
Handle<FeedbackCell> feedback_cell,
PretenureFlag pretenure = NOT_TENURED);
const Operator* CreateIterResultObject();
const Operator* CreateStringIterator();
const Operator* CreateKeyValueArray();
const Operator* CreatePromise();
const Operator* CreateLiteralArray(Handle<ConstantElementsPair> constant,
......
......@@ -515,6 +515,27 @@ MaybeHandle<Map> NodeProperties::GetMapWitness(Node* node) {
return MaybeHandle<Map>();
}
// static
bool NodeProperties::HasInstanceTypeWitness(Node* receiver, Node* effect,
InstanceType instance_type) {
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
switch (result) {
case NodeProperties::kUnreliableReceiverMaps:
case NodeProperties::kReliableReceiverMaps:
DCHECK_NE(0, receiver_maps.size());
for (size_t i = 0; i < receiver_maps.size(); ++i) {
if (receiver_maps[i]->instance_type() != instance_type) return false;
}
return true;
case NodeProperties::kNoReceiverMaps:
return false;
}
UNREACHABLE();
}
// static
bool NodeProperties::NoObservableSideEffectBetween(Node* effect,
Node* dominator) {
......
......@@ -155,6 +155,8 @@ class V8_EXPORT_PRIVATE NodeProperties final {
Node* receiver, Node* effect, ZoneHandleSet<Map>* maps_return);
static MaybeHandle<Map> GetMapWitness(Node* node);
static bool HasInstanceTypeWitness(Node* receiver, Node* effect,
InstanceType instance_type);
// Walks up the {effect} chain to check that there's no observable side-effect
// between the {effect} and it's {dominator}. Aborts the walk if there's join
......
......@@ -140,6 +140,7 @@
V(JSCreateClosure) \
V(JSCreateGeneratorObject) \
V(JSCreateIterResultObject) \
V(JSCreateStringIterator) \
V(JSCreateKeyValueArray) \
V(JSCreatePromise) \
V(JSCreateLiteralArray) \
......
......@@ -1225,6 +1225,10 @@ Type* Typer::Visitor::TypeJSCreateIterResultObject(Node* node) {
return Type::OtherObject();
}
Type* Typer::Visitor::TypeJSCreateStringIterator(Node* node) {
return Type::OtherObject();
}
Type* Typer::Visitor::TypeJSCreateKeyValueArray(Node* node) {
return Type::OtherObject();
}
......@@ -1958,9 +1962,13 @@ Type* Typer::Visitor::StringFromCodePointTyper(Type* type, Typer* t) {
Type* Typer::Visitor::TypeStringCharAt(Node* node) { return Type::String(); }
Type* Typer::Visitor::TypeStringToLowerCaseIntl(Node* node) { UNREACHABLE(); }
Type* Typer::Visitor::TypeStringToLowerCaseIntl(Node* node) {
return Type::String();
}
Type* Typer::Visitor::TypeStringToUpperCaseIntl(Node* node) { UNREACHABLE(); }
Type* Typer::Visitor::TypeStringToUpperCaseIntl(Node* node) {
return Type::String();
}
Type* Typer::Visitor::TypeStringCharCodeAt(Node* node) {
return typer_->cache_.kUint16;
......
......@@ -677,6 +677,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
// Type is OtherObject.
CheckTypeIs(node, Type::OtherObject());
break;
case IrOpcode::kJSCreateStringIterator:
// Type is OtherObject.
CheckTypeIs(node, Type::OtherObject());
break;
case IrOpcode::kJSCreateKeyValueArray:
// Type is OtherObject.
CheckTypeIs(node, Type::OtherObject());
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file.
// Flags: --allow-natives-syntax --opt --no-always-opt
(()=> {
function f(a, b, c) {
return a.indexOf(b, c);
}
f("abc", "de", 1);
f("abc", "de", 1);
%OptimizeFunctionOnNextCall(f);
f("abc", "de", {});
%OptimizeFunctionOnNextCall(f);
f("abc", "de", {});
assertOptimized(f);
})();
(()=> {
function f(a, b, c) {
return a.indexOf(b, c);
}
f("abc", "de", 1);
f("abc", "de", 1);
%OptimizeFunctionOnNextCall(f);
f("abc", {}, 1);
%OptimizeFunctionOnNextCall(f);
f("abc", {}, 1);
assertOptimized(f);
})();
......@@ -328,46 +328,6 @@ TEST_F(JSBuiltinReducerTest, NumberParseIntWithIntegral32AndUndefined) {
}
}
// -----------------------------------------------------------------------------
// String.fromCharCode
TEST_F(JSBuiltinReducerTest, StringFromCharCodeWithNumber) {
Node* function = StringFunction("fromCharCode");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call =
graph()->NewNode(javascript()->Call(3), function, UndefinedConstant(),
p0, context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsStringFromCharCode(p0));
}
}
TEST_F(JSBuiltinReducerTest, StringFromCharCodeWithPlainPrimitive) {
Node* function = StringFunction("fromCharCode");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call =
graph()->NewNode(javascript()->Call(3), function, UndefinedConstant(), p0,
context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsStringFromCharCode(IsPlainPrimitiveToNumber(p0)));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -67,6 +67,19 @@ class JSCallReducerTest : public TypedGraphTest {
return HeapConstant(f);
}
Node* StringFunction(const char* name) {
Handle<Object> m =
JSObject::GetProperty(
isolate()->global_object(),
isolate()->factory()->NewStringFromAsciiChecked("String"))
.ToHandleChecked();
Handle<JSFunction> f = Handle<JSFunction>::cast(
Object::GetProperty(
m, isolate()->factory()->NewStringFromAsciiChecked(name))
.ToHandleChecked());
return HeapConstant(f);
}
std::string op_name_for(const char* fnc) {
std::string string_fnc(fnc);
char initial = std::toupper(fnc[0]);
......@@ -391,6 +404,41 @@ TEST_F(JSCallReducerTest, MathMaxWithTwoArguments) {
IsSpeculativeToNumber(p1)));
}
// -----------------------------------------------------------------------------
// String.fromCharCode
TEST_F(JSCallReducerTest, StringFromCharCodeWithNumber) {
Node* function = StringFunction("fromCharCode");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::Any(), 0);
Node* call = graph()->NewNode(Call(3), function, UndefinedConstant(), p0,
context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsStringFromCharCode(IsSpeculativeToNumber(p0)));
}
TEST_F(JSCallReducerTest, StringFromCharCodeWithPlainPrimitive) {
Node* function = StringFunction("fromCharCode");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(Call(3), function, UndefinedConstant(), p0,
context, frame_state, effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsStringFromCharCode(IsSpeculativeToNumber(p0)));
}
} // namespace compiler
} // namespace internal
} // namespace v8
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