Commit 13dc483c authored by Jaroslav Sevcik's avatar Jaroslav Sevcik Committed by Commit Bot

[turbofan] Redundancy elimination of String.to(Lower|Upper)Case().

This is mainly to enable optimization of case-insensitive maps, where
we see the pattern

if (m.has(key.toLowerCase())) { return m.get(key.toLowerCase()) } ...

Cq-Include-Trybots: master.tryserver.v8:v8_linux_noi18n_rel_ng
Change-Id: I8c78a185401c51e8a53ae2932a158eaafa169495
Reviewed-on: https://chromium-review.googlesource.com/547057
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46206}
parent a2f5a740
...@@ -4145,19 +4145,17 @@ void Genesis::InitializeGlobal_icu_case_mapping() { ...@@ -4145,19 +4145,17 @@ void Genesis::InitializeGlobal_icu_case_mapping() {
{ {
Handle<String> name = factory()->InternalizeUtf8String("toLowerCase"); Handle<String> name = factory()->InternalizeUtf8String("toLowerCase");
SetFunction(string_prototype, Handle<JSFunction> to_lower_case = SimpleCreateFunction(
SimpleCreateFunction(isolate(), name, isolate(), name, Builtins::kStringPrototypeToLowerCaseIntl, 0, true);
Builtins::kStringPrototypeToLowerCaseIntl, SetFunction(string_prototype, to_lower_case, name);
0, true), to_lower_case->shared()->set_builtin_function_id(kStringToLowerCaseIntl);
name);
} }
{ {
Handle<String> name = factory()->InternalizeUtf8String("toUpperCase"); Handle<String> name = factory()->InternalizeUtf8String("toUpperCase");
SetFunction(string_prototype, Handle<JSFunction> to_upper_case = SimpleCreateFunction(
SimpleCreateFunction(isolate(), name, isolate(), name, Builtins::kStringPrototypeToUpperCaseIntl, 0, false);
Builtins::kStringPrototypeToUpperCaseIntl, SetFunction(string_prototype, to_upper_case, name);
0, false), to_upper_case->shared()->set_builtin_function_id(kStringToUpperCaseIntl);
name);
} }
Handle<JSFunction> to_locale_lower_case = Handle<JSFunction>::cast( Handle<JSFunction> to_locale_lower_case = Handle<JSFunction>::cast(
......
...@@ -1067,6 +1067,7 @@ namespace internal { ...@@ -1067,6 +1067,7 @@ namespace internal {
#define BUILTIN_LIST(CPP, API, TFJ, TFC, TFS, TFH, ASM, DBG) \ #define BUILTIN_LIST(CPP, API, TFJ, TFC, TFS, TFH, ASM, DBG) \
BUILTIN_LIST_BASE(CPP, API, TFJ, TFC, TFS, TFH, ASM, DBG) \ BUILTIN_LIST_BASE(CPP, API, TFJ, TFC, TFS, TFH, ASM, DBG) \
\ \
TFS(StringToLowerCaseIntl, kString) \
/* ES #sec-string.prototype.tolowercase */ \ /* ES #sec-string.prototype.tolowercase */ \
TFJ(StringPrototypeToLowerCaseIntl, 0) \ TFJ(StringPrototypeToLowerCaseIntl, 0) \
/* ES #sec-string.prototype.touppercase */ \ /* ES #sec-string.prototype.touppercase */ \
......
...@@ -18,12 +18,11 @@ class IntlBuiltinsAssembler : public CodeStubAssembler { ...@@ -18,12 +18,11 @@ class IntlBuiltinsAssembler : public CodeStubAssembler {
: CodeStubAssembler(state) {} : CodeStubAssembler(state) {}
}; };
TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) { TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
Node* const maybe_string = Parameter(Descriptor::kReceiver); Node* const string = Parameter(Descriptor::kString);
Node* const context = Parameter(Descriptor::kContext); Node* const context = Parameter(Descriptor::kContext);
Node* const string = CSA_ASSERT(this, IsString(string));
ToThisString(context, maybe_string, "String.prototype.toLowerCase");
Label call_c(this), return_string(this), runtime(this, Label::kDeferred); Label call_c(this), return_string(this), runtime(this, Label::kDeferred);
...@@ -64,17 +63,17 @@ TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) { ...@@ -64,17 +63,17 @@ TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) {
VARIABLE(var_did_change, MachineRepresentation::kWord32, Int32Constant(0)); VARIABLE(var_did_change, MachineRepresentation::kWord32, Int32Constant(0));
VariableList push_vars({&var_cursor, &var_did_change}, zone()); VariableList push_vars({&var_cursor, &var_did_change}, zone());
BuildFastLoop( BuildFastLoop(push_vars, start_address, end_address,
push_vars, start_address, end_address,
[=, &var_cursor, &var_did_change](Node* current) { [=, &var_cursor, &var_did_change](Node* current) {
Node* c = Load(MachineType::Uint8(), current); Node* c = Load(MachineType::Uint8(), current);
Node* lower = Load(MachineType::Uint8(), to_lower_table_addr, Node* lower =
Load(MachineType::Uint8(), to_lower_table_addr,
ChangeInt32ToIntPtr(c)); ChangeInt32ToIntPtr(c));
StoreNoWriteBarrier(MachineRepresentation::kWord8, dst_ptr, StoreNoWriteBarrier(MachineRepresentation::kWord8, dst_ptr,
var_cursor.value(), lower); var_cursor.value(), lower);
var_did_change.Bind( var_did_change.Bind(Word32Or(Word32NotEqual(c, lower),
Word32Or(Word32NotEqual(c, lower), var_did_change.value())); var_did_change.value()));
Increment(var_cursor); Increment(var_cursor);
}, },
...@@ -114,11 +113,21 @@ TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) { ...@@ -114,11 +113,21 @@ TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) {
BIND(&runtime); BIND(&runtime);
{ {
Node* const result = Node* const result = CallRuntime(Runtime::kStringToLowerCaseIntl,
CallRuntime(Runtime::kStringToLowerCaseIntl, context, string); NoContextConstant(), string);
Return(result); Return(result);
} }
} }
TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) {
Node* const maybe_string = Parameter(Descriptor::kReceiver);
Node* const context = Parameter(Descriptor::kContext);
Node* const string =
ToThisString(context, maybe_string, "String.prototype.toLowerCase");
Return(CallBuiltin(Builtins::kStringToLowerCaseIntl, context, string));
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -1759,11 +1759,25 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length, ...@@ -1759,11 +1759,25 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length,
return result; return result;
} }
Node* CodeStubAssembler::IsZeroOrFixedArray(Node* object) {
Label out(this);
VARIABLE(var_result, MachineRepresentation::kWord32, Int32Constant(1));
GotoIf(WordEqual(object, SmiConstant(Smi::kZero)), &out);
GotoIf(IsFixedArray(object), &out);
var_result.Bind(Int32Constant(0));
Goto(&out);
BIND(&out);
return var_result.value();
}
Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length, Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length,
ParameterMode mode, ParameterMode mode,
AllocationFlags flags) { AllocationFlags flags) {
Comment("AllocateSeqOneByteString"); Comment("AllocateSeqOneByteString");
CSA_SLOW_ASSERT(this, IsFixedArray(context)); CSA_SLOW_ASSERT(this, IsZeroOrFixedArray(context));
CSA_SLOW_ASSERT(this, MatchesParameterMode(length, mode)); CSA_SLOW_ASSERT(this, MatchesParameterMode(length, mode));
VARIABLE(var_result, MachineRepresentation::kTagged); VARIABLE(var_result, MachineRepresentation::kTagged);
......
...@@ -784,6 +784,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { ...@@ -784,6 +784,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsFixedArrayWithKindOrEmpty(Node* object, ElementsKind kind); Node* IsFixedArrayWithKindOrEmpty(Node* object, ElementsKind kind);
Node* IsFixedDoubleArray(Node* object); Node* IsFixedDoubleArray(Node* object);
Node* IsFixedTypedArray(Node* object); Node* IsFixedTypedArray(Node* object);
Node* IsZeroOrFixedArray(Node* object);
Node* IsHashTable(Node* object); Node* IsHashTable(Node* object);
Node* IsHeapNumber(Node* object); Node* IsHeapNumber(Node* object);
Node* IsIndirectStringInstanceType(Node* instance_type); Node* IsIndirectStringInstanceType(Node* instance_type);
......
...@@ -775,6 +775,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -775,6 +775,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kSeqStringCharCodeAt: case IrOpcode::kSeqStringCharCodeAt:
result = LowerSeqStringCharCodeAt(node); result = LowerSeqStringCharCodeAt(node);
break; break;
case IrOpcode::kStringToLowerCaseIntl:
result = LowerStringToLowerCaseIntl(node);
break;
case IrOpcode::kStringToUpperCaseIntl:
result = LowerStringToUpperCaseIntl(node);
break;
case IrOpcode::kStringEqual: case IrOpcode::kStringEqual:
result = LowerStringEqual(node); result = LowerStringEqual(node);
break; break;
...@@ -2255,6 +2261,46 @@ Node* EffectControlLinearizer::LowerStringFromCharCode(Node* node) { ...@@ -2255,6 +2261,46 @@ Node* EffectControlLinearizer::LowerStringFromCharCode(Node* node) {
return done.PhiAt(0); return done.PhiAt(0);
} }
#ifdef V8_INTL_SUPPORT
Node* EffectControlLinearizer::LowerStringToLowerCaseIntl(Node* node) {
Node* receiver = node->InputAt(0);
Callable callable =
Builtins::CallableFor(isolate(), Builtins::kStringToLowerCaseIntl);
Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
return __ Call(desc, __ HeapConstant(callable.code()), receiver,
__ NoContextConstant());
}
Node* EffectControlLinearizer::LowerStringToUpperCaseIntl(Node* node) {
Node* receiver = node->InputAt(0);
Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
Runtime::FunctionId id = Runtime::kStringToUpperCaseIntl;
CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
return __ Call(desc, __ CEntryStubConstant(1), receiver,
__ ExternalConstant(ExternalReference(id, isolate())),
__ Int32Constant(1), __ NoContextConstant());
}
#else
Node* EffectControlLinearizer::LowerStringToLowerCaseIntl(Node* node) {
UNREACHABLE();
return nullptr;
}
Node* EffectControlLinearizer::LowerStringToUpperCaseIntl(Node* node) {
UNREACHABLE();
return nullptr;
}
#endif // V8_INTL_SUPPORT
Node* EffectControlLinearizer::LowerStringFromCodePoint(Node* node) { Node* EffectControlLinearizer::LowerStringFromCodePoint(Node* node) {
Node* value = node->InputAt(0); Node* value = node->InputAt(0);
Node* code = value; Node* code = value;
......
...@@ -100,6 +100,8 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer { ...@@ -100,6 +100,8 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerStringCharAt(Node* node); Node* LowerStringCharAt(Node* node);
Node* LowerStringCharCodeAt(Node* node); Node* LowerStringCharCodeAt(Node* node);
Node* LowerSeqStringCharCodeAt(Node* node); Node* LowerSeqStringCharCodeAt(Node* node);
Node* LowerStringToLowerCaseIntl(Node* node);
Node* LowerStringToUpperCaseIntl(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);
......
...@@ -2368,6 +2368,30 @@ Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) { ...@@ -2368,6 +2368,30 @@ Reduction JSBuiltinReducer::ReduceStringIteratorNext(Node* node) {
return NoChange(); 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::ReduceArrayBufferViewAccessor( Reduction JSBuiltinReducer::ReduceArrayBufferViewAccessor(
Node* node, InstanceType instance_type, FieldAccess const& access) { Node* node, InstanceType instance_type, FieldAccess const& access) {
Node* receiver = NodeProperties::GetValueInput(node, 1); Node* receiver = NodeProperties::GetValueInput(node, 1);
...@@ -2572,6 +2596,10 @@ Reduction JSBuiltinReducer::Reduce(Node* node) { ...@@ -2572,6 +2596,10 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceStringIterator(node); return ReduceStringIterator(node);
case kStringIteratorNext: case kStringIteratorNext:
return ReduceStringIteratorNext(node); return ReduceStringIteratorNext(node);
case kStringToLowerCaseIntl:
return ReduceStringToLowerCaseIntl(node);
case kStringToUpperCaseIntl:
return ReduceStringToUpperCaseIntl(node);
case kDataViewByteLength: case kDataViewByteLength:
return ReduceArrayBufferViewAccessor( return ReduceArrayBufferViewAccessor(
node, JS_DATA_VIEW_TYPE, node, JS_DATA_VIEW_TYPE,
......
...@@ -110,6 +110,8 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final ...@@ -110,6 +110,8 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
Reduction ReduceStringIndexOf(Node* node); Reduction ReduceStringIndexOf(Node* node);
Reduction ReduceStringIterator(Node* node); Reduction ReduceStringIterator(Node* node);
Reduction ReduceStringIteratorNext(Node* node); Reduction ReduceStringIteratorNext(Node* node);
Reduction ReduceStringToLowerCaseIntl(Node* node);
Reduction ReduceStringToUpperCaseIntl(Node* node);
Reduction ReduceArrayBufferViewAccessor(Node* node, Reduction ReduceArrayBufferViewAccessor(Node* node,
InstanceType instance_type, InstanceType instance_type,
FieldAccess const& access); FieldAccess const& access);
......
...@@ -320,6 +320,8 @@ ...@@ -320,6 +320,8 @@
V(StringFromCharCode) \ V(StringFromCharCode) \
V(StringFromCodePoint) \ V(StringFromCodePoint) \
V(StringIndexOf) \ V(StringIndexOf) \
V(StringToLowerCaseIntl) \
V(StringToUpperCaseIntl) \
V(CheckBounds) \ V(CheckBounds) \
V(CheckIf) \ V(CheckIf) \
V(CheckMaps) \ V(CheckMaps) \
......
...@@ -2368,7 +2368,12 @@ class RepresentationSelector { ...@@ -2368,7 +2368,12 @@ class RepresentationSelector {
SetOutput(node, MachineRepresentation::kTaggedSigned); SetOutput(node, MachineRepresentation::kTaggedSigned);
return; return;
} }
case IrOpcode::kStringToLowerCaseIntl:
case IrOpcode::kStringToUpperCaseIntl: {
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kCheckBounds: { case IrOpcode::kCheckBounds: {
Type* index_type = TypeOf(node->InputAt(0)); Type* index_type = TypeOf(node->InputAt(0));
Type* length_type = TypeOf(node->InputAt(1)); Type* length_type = TypeOf(node->InputAt(1));
......
...@@ -477,6 +477,8 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) { ...@@ -477,6 +477,8 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
V(SeqStringCharCodeAt, 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(StringToLowerCaseIntl, Operator::kNoProperties, 1, 0) \
V(StringToUpperCaseIntl, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \ V(PlainPrimitiveToNumber, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \ V(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \ V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \
......
...@@ -382,6 +382,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -382,6 +382,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringFromCharCode(); const Operator* StringFromCharCode();
const Operator* StringFromCodePoint(UnicodeEncoding encoding); const Operator* StringFromCodePoint(UnicodeEncoding encoding);
const Operator* StringIndexOf(); const Operator* StringIndexOf();
const Operator* StringToLowerCaseIntl();
const Operator* StringToUpperCaseIntl();
const Operator* SpeculativeToNumber(NumberOperationHint hint); const Operator* SpeculativeToNumber(NumberOperationHint hint);
......
...@@ -1800,6 +1800,10 @@ Type* Typer::Visitor::StringFromCodePointTyper(Type* type, Typer* t) { ...@@ -1800,6 +1800,10 @@ Type* Typer::Visitor::StringFromCodePointTyper(Type* type, Typer* t) {
Type* Typer::Visitor::TypeStringCharAt(Node* node) { return Type::String(); } Type* Typer::Visitor::TypeStringCharAt(Node* node) { return Type::String(); }
Type* Typer::Visitor::TypeStringToLowerCaseIntl(Node* node) { UNREACHABLE(); }
Type* Typer::Visitor::TypeStringToUpperCaseIntl(Node* node) { UNREACHABLE(); }
Type* Typer::Visitor::TypeStringCharCodeAt(Node* node) { Type* Typer::Visitor::TypeStringCharCodeAt(Node* node) {
return typer_->cache_.kUint16; return typer_->cache_.kUint16;
} }
......
...@@ -989,6 +989,11 @@ void Verifier::Visitor::Check(Node* node) { ...@@ -989,6 +989,11 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 2, Type::SignedSmall()); CheckValueInputIs(node, 2, Type::SignedSmall());
CheckTypeIs(node, Type::SignedSmall()); CheckTypeIs(node, Type::SignedSmall());
break; break;
case IrOpcode::kStringToLowerCaseIntl:
case IrOpcode::kStringToUpperCaseIntl:
CheckValueInputIs(node, 0, Type::String());
CheckTypeIs(node, Type::String());
break;
case IrOpcode::kReferenceEqual: case IrOpcode::kReferenceEqual:
// (Unique, Any) -> Boolean and // (Unique, Any) -> Boolean and
......
...@@ -4697,6 +4697,8 @@ enum BuiltinFunctionId { ...@@ -4697,6 +4697,8 @@ enum BuiltinFunctionId {
kSharedArrayBufferByteLength, kSharedArrayBufferByteLength,
kStringIterator, kStringIterator,
kStringIteratorNext, kStringIteratorNext,
kStringToLowerCaseIntl,
kStringToUpperCaseIntl
}; };
class JSGeneratorObject: public JSObject { class JSGeneratorObject: public JSObject {
......
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