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() {
{
Handle<String> name = factory()->InternalizeUtf8String("toLowerCase");
SetFunction(string_prototype,
SimpleCreateFunction(isolate(), name,
Builtins::kStringPrototypeToLowerCaseIntl,
0, true),
name);
Handle<JSFunction> to_lower_case = SimpleCreateFunction(
isolate(), name, Builtins::kStringPrototypeToLowerCaseIntl, 0, true);
SetFunction(string_prototype, to_lower_case, name);
to_lower_case->shared()->set_builtin_function_id(kStringToLowerCaseIntl);
}
{
Handle<String> name = factory()->InternalizeUtf8String("toUpperCase");
SetFunction(string_prototype,
SimpleCreateFunction(isolate(), name,
Builtins::kStringPrototypeToUpperCaseIntl,
0, false),
name);
Handle<JSFunction> to_upper_case = SimpleCreateFunction(
isolate(), name, Builtins::kStringPrototypeToUpperCaseIntl, 0, false);
SetFunction(string_prototype, to_upper_case, name);
to_upper_case->shared()->set_builtin_function_id(kStringToUpperCaseIntl);
}
Handle<JSFunction> to_locale_lower_case = Handle<JSFunction>::cast(
......
......@@ -1067,6 +1067,7 @@ namespace internal {
#define BUILTIN_LIST(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 */ \
TFJ(StringPrototypeToLowerCaseIntl, 0) \
/* ES #sec-string.prototype.touppercase */ \
......
......@@ -18,12 +18,11 @@ class IntlBuiltinsAssembler : public CodeStubAssembler {
: CodeStubAssembler(state) {}
};
TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) {
Node* const maybe_string = Parameter(Descriptor::kReceiver);
TF_BUILTIN(StringToLowerCaseIntl, IntlBuiltinsAssembler) {
Node* const string = Parameter(Descriptor::kString);
Node* const context = Parameter(Descriptor::kContext);
Node* const string =
ToThisString(context, maybe_string, "String.prototype.toLowerCase");
CSA_ASSERT(this, IsString(string));
Label call_c(this), return_string(this), runtime(this, Label::kDeferred);
......@@ -64,17 +63,17 @@ TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) {
VARIABLE(var_did_change, MachineRepresentation::kWord32, Int32Constant(0));
VariableList push_vars({&var_cursor, &var_did_change}, zone());
BuildFastLoop(
push_vars, start_address, end_address,
BuildFastLoop(push_vars, start_address, end_address,
[=, &var_cursor, &var_did_change](Node* 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));
StoreNoWriteBarrier(MachineRepresentation::kWord8, dst_ptr,
var_cursor.value(), lower);
var_did_change.Bind(
Word32Or(Word32NotEqual(c, lower), var_did_change.value()));
var_did_change.Bind(Word32Or(Word32NotEqual(c, lower),
var_did_change.value()));
Increment(var_cursor);
},
......@@ -114,11 +113,21 @@ TF_BUILTIN(StringPrototypeToLowerCaseIntl, IntlBuiltinsAssembler) {
BIND(&runtime);
{
Node* const result =
CallRuntime(Runtime::kStringToLowerCaseIntl, context, string);
Node* const result = CallRuntime(Runtime::kStringToLowerCaseIntl,
NoContextConstant(), string);
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 v8
......@@ -1759,11 +1759,25 @@ Node* CodeStubAssembler::AllocateSeqOneByteString(int length,
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,
ParameterMode mode,
AllocationFlags flags) {
Comment("AllocateSeqOneByteString");
CSA_SLOW_ASSERT(this, IsFixedArray(context));
CSA_SLOW_ASSERT(this, IsZeroOrFixedArray(context));
CSA_SLOW_ASSERT(this, MatchesParameterMode(length, mode));
VARIABLE(var_result, MachineRepresentation::kTagged);
......
......@@ -784,6 +784,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* IsFixedArrayWithKindOrEmpty(Node* object, ElementsKind kind);
Node* IsFixedDoubleArray(Node* object);
Node* IsFixedTypedArray(Node* object);
Node* IsZeroOrFixedArray(Node* object);
Node* IsHashTable(Node* object);
Node* IsHeapNumber(Node* object);
Node* IsIndirectStringInstanceType(Node* instance_type);
......
......@@ -775,6 +775,12 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kSeqStringCharCodeAt:
result = LowerSeqStringCharCodeAt(node);
break;
case IrOpcode::kStringToLowerCaseIntl:
result = LowerStringToLowerCaseIntl(node);
break;
case IrOpcode::kStringToUpperCaseIntl:
result = LowerStringToUpperCaseIntl(node);
break;
case IrOpcode::kStringEqual:
result = LowerStringEqual(node);
break;
......@@ -2255,6 +2261,46 @@ Node* EffectControlLinearizer::LowerStringFromCharCode(Node* node) {
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* value = node->InputAt(0);
Node* code = value;
......
......@@ -100,6 +100,8 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* LowerStringCharAt(Node* node);
Node* LowerStringCharCodeAt(Node* node);
Node* LowerSeqStringCharCodeAt(Node* node);
Node* LowerStringToLowerCaseIntl(Node* node);
Node* LowerStringToUpperCaseIntl(Node* node);
Node* LowerStringFromCharCode(Node* node);
Node* LowerStringFromCodePoint(Node* node);
Node* LowerStringIndexOf(Node* node);
......
......@@ -2368,6 +2368,30 @@ Reduction JSBuiltinReducer::ReduceStringIteratorNext(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::ReduceArrayBufferViewAccessor(
Node* node, InstanceType instance_type, FieldAccess const& access) {
Node* receiver = NodeProperties::GetValueInput(node, 1);
......@@ -2572,6 +2596,10 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
return ReduceStringIterator(node);
case kStringIteratorNext:
return ReduceStringIteratorNext(node);
case kStringToLowerCaseIntl:
return ReduceStringToLowerCaseIntl(node);
case kStringToUpperCaseIntl:
return ReduceStringToUpperCaseIntl(node);
case kDataViewByteLength:
return ReduceArrayBufferViewAccessor(
node, JS_DATA_VIEW_TYPE,
......
......@@ -110,6 +110,8 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
Reduction ReduceStringIndexOf(Node* node);
Reduction ReduceStringIterator(Node* node);
Reduction ReduceStringIteratorNext(Node* node);
Reduction ReduceStringToLowerCaseIntl(Node* node);
Reduction ReduceStringToUpperCaseIntl(Node* node);
Reduction ReduceArrayBufferViewAccessor(Node* node,
InstanceType instance_type,
FieldAccess const& access);
......
......@@ -320,6 +320,8 @@
V(StringFromCharCode) \
V(StringFromCodePoint) \
V(StringIndexOf) \
V(StringToLowerCaseIntl) \
V(StringToUpperCaseIntl) \
V(CheckBounds) \
V(CheckIf) \
V(CheckMaps) \
......
......@@ -2368,7 +2368,12 @@ class RepresentationSelector {
SetOutput(node, MachineRepresentation::kTaggedSigned);
return;
}
case IrOpcode::kStringToLowerCaseIntl:
case IrOpcode::kStringToUpperCaseIntl: {
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kCheckBounds: {
Type* index_type = TypeOf(node->InputAt(0));
Type* length_type = TypeOf(node->InputAt(1));
......
......@@ -477,6 +477,8 @@ UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
V(SeqStringCharCodeAt, Operator::kNoProperties, 2, 1) \
V(StringFromCharCode, Operator::kNoProperties, 1, 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(PlainPrimitiveToWord32, Operator::kNoProperties, 1, 0) \
V(PlainPrimitiveToFloat64, Operator::kNoProperties, 1, 0) \
......
......@@ -382,6 +382,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* StringFromCharCode();
const Operator* StringFromCodePoint(UnicodeEncoding encoding);
const Operator* StringIndexOf();
const Operator* StringToLowerCaseIntl();
const Operator* StringToUpperCaseIntl();
const Operator* SpeculativeToNumber(NumberOperationHint hint);
......
......@@ -1800,6 +1800,10 @@ 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::TypeStringToUpperCaseIntl(Node* node) { UNREACHABLE(); }
Type* Typer::Visitor::TypeStringCharCodeAt(Node* node) {
return typer_->cache_.kUint16;
}
......
......@@ -989,6 +989,11 @@ void Verifier::Visitor::Check(Node* node) {
CheckValueInputIs(node, 2, Type::SignedSmall());
CheckTypeIs(node, Type::SignedSmall());
break;
case IrOpcode::kStringToLowerCaseIntl:
case IrOpcode::kStringToUpperCaseIntl:
CheckValueInputIs(node, 0, Type::String());
CheckTypeIs(node, Type::String());
break;
case IrOpcode::kReferenceEqual:
// (Unique, Any) -> Boolean and
......
......@@ -4697,6 +4697,8 @@ enum BuiltinFunctionId {
kSharedArrayBufferByteLength,
kStringIterator,
kStringIteratorNext,
kStringToLowerCaseIntl,
kStringToUpperCaseIntl
};
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