Commit c176b26f authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Lower StringEqual and friends in EffectControlLinearizer.

Turn the StringEqualStub and friends into proper TurboFan builtins,
which means that we don't need to do on-demand compilation for those
stubs, and use those to defer lowering of the StringEqual, etc.
simplified operators to effect/control linearization (i.e. move it to
the concurrent recompilation part).

BUG=v8:5428
R=jarin@chromium.org

Review-Url: https://codereview.chromium.org/2363333003
Cr-Commit-Position: refs/heads/master@{#39762}
parent c9cc3d16
......@@ -10,6 +10,408 @@
namespace v8 {
namespace internal {
namespace {
enum ResultMode { kDontNegateResult, kNegateResult };
void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
// Here's pseudo-code for the algorithm below in case of kDontNegateResult
// mode; for kNegateResult mode we properly negate the result.
//
// if (lhs == rhs) return true;
// if (lhs->length() != rhs->length()) return false;
// if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
// return false;
// }
// if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
// for (i = 0; i != lhs->length(); ++i) {
// if (lhs[i] != rhs[i]) return false;
// }
// return true;
// }
// return %StringEqual(lhs, rhs);
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Label if_equal(assembler), if_notequal(assembler);
// Fast check to see if {lhs} and {rhs} refer to the same String object.
Label if_same(assembler), if_notsame(assembler);
assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
assembler->Bind(&if_same);
assembler->Goto(&if_equal);
assembler->Bind(&if_notsame);
{
// The {lhs} and {rhs} don't refer to the exact same String object.
// Load the length of {lhs} and {rhs}.
Node* lhs_length = assembler->LoadStringLength(lhs);
Node* rhs_length = assembler->LoadStringLength(rhs);
// Check if the lengths of {lhs} and {rhs} are equal.
Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
&if_lengthisequal, &if_lengthisnotequal);
assembler->Bind(&if_lengthisequal);
{
// Load instance types of {lhs} and {rhs}.
Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
// Combine the instance types into a single 16-bit value, so we can check
// both of them at once.
Node* both_instance_types = assembler->Word32Or(
lhs_instance_type,
assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
// Check if both {lhs} and {rhs} are internalized.
int const kBothInternalizedMask =
kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
int const kBothInternalizedTag =
kInternalizedTag | (kInternalizedTag << 8);
Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
assembler->Branch(assembler->Word32Equal(
assembler->Word32And(both_instance_types,
assembler->Int32Constant(
kBothInternalizedMask)),
assembler->Int32Constant(kBothInternalizedTag)),
&if_bothinternalized, &if_notbothinternalized);
assembler->Bind(&if_bothinternalized);
{
// Fast negative check for internalized-to-internalized equality.
assembler->Goto(&if_notequal);
}
assembler->Bind(&if_notbothinternalized);
{
// Check that both {lhs} and {rhs} are flat one-byte strings.
int const kBothSeqOneByteStringMask =
kStringEncodingMask | kStringRepresentationMask |
((kStringEncodingMask | kStringRepresentationMask) << 8);
int const kBothSeqOneByteStringTag =
kOneByteStringTag | kSeqStringTag |
((kOneByteStringTag | kSeqStringTag) << 8);
Label if_bothonebyteseqstrings(assembler),
if_notbothonebyteseqstrings(assembler);
assembler->Branch(
assembler->Word32Equal(
assembler->Word32And(
both_instance_types,
assembler->Int32Constant(kBothSeqOneByteStringMask)),
assembler->Int32Constant(kBothSeqOneByteStringTag)),
&if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
assembler->Bind(&if_bothonebyteseqstrings);
{
// Compute the effective offset of the first character.
Node* begin = assembler->IntPtrConstant(
SeqOneByteString::kHeaderSize - kHeapObjectTag);
// Compute the first offset after the string from the length.
Node* end =
assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
// Loop over the {lhs} and {rhs} strings to see if they are equal.
Variable var_offset(assembler, MachineType::PointerRepresentation());
Label loop(assembler, &var_offset);
var_offset.Bind(begin);
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Check if {offset} equals {end}.
Node* offset = var_offset.value();
Label if_done(assembler), if_notdone(assembler);
assembler->Branch(assembler->WordEqual(offset, end), &if_done,
&if_notdone);
assembler->Bind(&if_notdone);
{
// Load the next characters from {lhs} and {rhs}.
Node* lhs_value =
assembler->Load(MachineType::Uint8(), lhs, offset);
Node* rhs_value =
assembler->Load(MachineType::Uint8(), rhs, offset);
// Check if the characters match.
Label if_valueissame(assembler), if_valueisnotsame(assembler);
assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
&if_valueissame, &if_valueisnotsame);
assembler->Bind(&if_valueissame);
{
// Advance to next character.
var_offset.Bind(
assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
}
assembler->Goto(&loop);
assembler->Bind(&if_valueisnotsame);
assembler->Goto(&if_notequal);
}
assembler->Bind(&if_done);
assembler->Goto(&if_equal);
}
}
assembler->Bind(&if_notbothonebyteseqstrings);
{
// TODO(bmeurer): Add fast case support for flattened cons strings;
// also add support for two byte string equality checks.
Runtime::FunctionId function_id = (mode == kDontNegateResult)
? Runtime::kStringEqual
: Runtime::kStringNotEqual;
assembler->TailCallRuntime(function_id, context, lhs, rhs);
}
}
}
assembler->Bind(&if_lengthisnotequal);
{
// Mismatch in length of {lhs} and {rhs}, cannot be equal.
assembler->Goto(&if_notequal);
}
}
assembler->Bind(&if_equal);
assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
assembler->Bind(&if_notequal);
assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
}
enum RelationalComparisonMode {
kLessThan,
kLessThanOrEqual,
kGreaterThan,
kGreaterThanOrEqual
};
void GenerateStringRelationalComparison(CodeStubAssembler* assembler,
RelationalComparisonMode mode) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Label if_less(assembler), if_equal(assembler), if_greater(assembler);
// Fast check to see if {lhs} and {rhs} refer to the same String object.
Label if_same(assembler), if_notsame(assembler);
assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
assembler->Bind(&if_same);
assembler->Goto(&if_equal);
assembler->Bind(&if_notsame);
{
// Load instance types of {lhs} and {rhs}.
Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
// Combine the instance types into a single 16-bit value, so we can check
// both of them at once.
Node* both_instance_types = assembler->Word32Or(
lhs_instance_type,
assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
// Check that both {lhs} and {rhs} are flat one-byte strings.
int const kBothSeqOneByteStringMask =
kStringEncodingMask | kStringRepresentationMask |
((kStringEncodingMask | kStringRepresentationMask) << 8);
int const kBothSeqOneByteStringTag =
kOneByteStringTag | kSeqStringTag |
((kOneByteStringTag | kSeqStringTag) << 8);
Label if_bothonebyteseqstrings(assembler),
if_notbothonebyteseqstrings(assembler);
assembler->Branch(assembler->Word32Equal(
assembler->Word32And(both_instance_types,
assembler->Int32Constant(
kBothSeqOneByteStringMask)),
assembler->Int32Constant(kBothSeqOneByteStringTag)),
&if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
assembler->Bind(&if_bothonebyteseqstrings);
{
// Load the length of {lhs} and {rhs}.
Node* lhs_length = assembler->LoadStringLength(lhs);
Node* rhs_length = assembler->LoadStringLength(rhs);
// Determine the minimum length.
Node* length = assembler->SmiMin(lhs_length, rhs_length);
// Compute the effective offset of the first character.
Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag);
// Compute the first offset after the string from the length.
Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
// Loop over the {lhs} and {rhs} strings to see if they are equal.
Variable var_offset(assembler, MachineType::PointerRepresentation());
Label loop(assembler, &var_offset);
var_offset.Bind(begin);
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Check if {offset} equals {end}.
Node* offset = var_offset.value();
Label if_done(assembler), if_notdone(assembler);
assembler->Branch(assembler->WordEqual(offset, end), &if_done,
&if_notdone);
assembler->Bind(&if_notdone);
{
// Load the next characters from {lhs} and {rhs}.
Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
// Check if the characters match.
Label if_valueissame(assembler), if_valueisnotsame(assembler);
assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
&if_valueissame, &if_valueisnotsame);
assembler->Bind(&if_valueissame);
{
// Advance to next character.
var_offset.Bind(
assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
}
assembler->Goto(&loop);
assembler->Bind(&if_valueisnotsame);
assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value),
&if_less, &if_greater);
}
assembler->Bind(&if_done);
{
// All characters up to the min length are equal, decide based on
// string length.
Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
&if_lengthisequal, &if_lengthisnotequal);
assembler->Bind(&if_lengthisequal);
assembler->Goto(&if_equal);
assembler->Bind(&if_lengthisnotequal);
assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
&if_greater);
}
}
}
assembler->Bind(&if_notbothonebyteseqstrings);
{
// TODO(bmeurer): Add fast case support for flattened cons strings;
// also add support for two byte string relational comparisons.
switch (mode) {
case kLessThan:
assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
rhs);
break;
case kLessThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
lhs, rhs);
break;
case kGreaterThan:
assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
rhs);
break;
case kGreaterThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
context, lhs, rhs);
break;
}
}
}
assembler->Bind(&if_less);
switch (mode) {
case kLessThan:
case kLessThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
case kGreaterThan:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(false));
break;
}
assembler->Bind(&if_equal);
switch (mode) {
case kLessThan:
case kGreaterThan:
assembler->Return(assembler->BooleanConstant(false));
break;
case kLessThanOrEqual:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
}
assembler->Bind(&if_greater);
switch (mode) {
case kLessThan:
case kLessThanOrEqual:
assembler->Return(assembler->BooleanConstant(false));
break;
case kGreaterThan:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
}
}
} // namespace
// static
void Builtins::Generate_StringEqual(CodeStubAssembler* assembler) {
GenerateStringEqual(assembler, kDontNegateResult);
}
// static
void Builtins::Generate_StringNotEqual(CodeStubAssembler* assembler) {
GenerateStringEqual(assembler, kNegateResult);
}
// static
void Builtins::Generate_StringLessThan(CodeStubAssembler* assembler) {
GenerateStringRelationalComparison(assembler, kLessThan);
}
// static
void Builtins::Generate_StringLessThanOrEqual(CodeStubAssembler* assembler) {
GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
}
// static
void Builtins::Generate_StringGreaterThan(CodeStubAssembler* assembler) {
GenerateStringRelationalComparison(assembler, kGreaterThan);
}
// static
void Builtins::Generate_StringGreaterThanOrEqual(CodeStubAssembler* assembler) {
GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
}
// -----------------------------------------------------------------------------
// ES6 section 21.1 String Objects
......
......@@ -97,6 +97,14 @@ namespace internal {
ASM(InterruptCheck) \
ASM(StackCheck) \
\
/* String helpers */ \
TFS(StringEqual, BUILTIN, kNoExtraICState, Compare) \
TFS(StringNotEqual, BUILTIN, kNoExtraICState, Compare) \
TFS(StringLessThan, BUILTIN, kNoExtraICState, Compare) \
TFS(StringLessThanOrEqual, BUILTIN, kNoExtraICState, Compare) \
TFS(StringGreaterThan, BUILTIN, kNoExtraICState, Compare) \
TFS(StringGreaterThanOrEqual, BUILTIN, kNoExtraICState, Compare) \
\
/* Interpreter */ \
ASM(InterpreterEntryTrampoline) \
ASM(InterpreterMarkBaselineOnReturn) \
......
......@@ -410,38 +410,38 @@ Callable CodeFactory::StringCompare(Isolate* isolate, Token::Value token) {
// static
Callable CodeFactory::StringEqual(Isolate* isolate) {
StringEqualStub stub(isolate);
return make_callable(stub);
return Callable(isolate->builtins()->StringEqual(),
CompareDescriptor(isolate));
}
// static
Callable CodeFactory::StringNotEqual(Isolate* isolate) {
StringNotEqualStub stub(isolate);
return make_callable(stub);
return Callable(isolate->builtins()->StringNotEqual(),
CompareDescriptor(isolate));
}
// static
Callable CodeFactory::StringLessThan(Isolate* isolate) {
StringLessThanStub stub(isolate);
return make_callable(stub);
return Callable(isolate->builtins()->StringLessThan(),
CompareDescriptor(isolate));
}
// static
Callable CodeFactory::StringLessThanOrEqual(Isolate* isolate) {
StringLessThanOrEqualStub stub(isolate);
return make_callable(stub);
return Callable(isolate->builtins()->StringLessThanOrEqual(),
CompareDescriptor(isolate));
}
// static
Callable CodeFactory::StringGreaterThan(Isolate* isolate) {
StringGreaterThanStub stub(isolate);
return make_callable(stub);
return Callable(isolate->builtins()->StringGreaterThan(),
CompareDescriptor(isolate));
}
// static
Callable CodeFactory::StringGreaterThanOrEqual(Isolate* isolate) {
StringGreaterThanOrEqualStub stub(isolate);
return make_callable(stub);
return Callable(isolate->builtins()->StringGreaterThanOrEqual(),
CompareDescriptor(isolate));
}
// static
......
......@@ -4188,365 +4188,6 @@ compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler,
return result.value();
}
void GenerateStringRelationalComparison(CodeStubAssembler* assembler,
RelationalComparisonMode mode) {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Label if_less(assembler), if_equal(assembler), if_greater(assembler);
// Fast check to see if {lhs} and {rhs} refer to the same String object.
Label if_same(assembler), if_notsame(assembler);
assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
assembler->Bind(&if_same);
assembler->Goto(&if_equal);
assembler->Bind(&if_notsame);
{
// Load instance types of {lhs} and {rhs}.
Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
// Combine the instance types into a single 16-bit value, so we can check
// both of them at once.
Node* both_instance_types = assembler->Word32Or(
lhs_instance_type,
assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
// Check that both {lhs} and {rhs} are flat one-byte strings.
int const kBothSeqOneByteStringMask =
kStringEncodingMask | kStringRepresentationMask |
((kStringEncodingMask | kStringRepresentationMask) << 8);
int const kBothSeqOneByteStringTag =
kOneByteStringTag | kSeqStringTag |
((kOneByteStringTag | kSeqStringTag) << 8);
Label if_bothonebyteseqstrings(assembler),
if_notbothonebyteseqstrings(assembler);
assembler->Branch(assembler->Word32Equal(
assembler->Word32And(both_instance_types,
assembler->Int32Constant(
kBothSeqOneByteStringMask)),
assembler->Int32Constant(kBothSeqOneByteStringTag)),
&if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
assembler->Bind(&if_bothonebyteseqstrings);
{
// Load the length of {lhs} and {rhs}.
Node* lhs_length = assembler->LoadStringLength(lhs);
Node* rhs_length = assembler->LoadStringLength(rhs);
// Determine the minimum length.
Node* length = assembler->SmiMin(lhs_length, rhs_length);
// Compute the effective offset of the first character.
Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag);
// Compute the first offset after the string from the length.
Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
// Loop over the {lhs} and {rhs} strings to see if they are equal.
Variable var_offset(assembler, MachineType::PointerRepresentation());
Label loop(assembler, &var_offset);
var_offset.Bind(begin);
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Check if {offset} equals {end}.
Node* offset = var_offset.value();
Label if_done(assembler), if_notdone(assembler);
assembler->Branch(assembler->WordEqual(offset, end), &if_done,
&if_notdone);
assembler->Bind(&if_notdone);
{
// Load the next characters from {lhs} and {rhs}.
Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
// Check if the characters match.
Label if_valueissame(assembler), if_valueisnotsame(assembler);
assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
&if_valueissame, &if_valueisnotsame);
assembler->Bind(&if_valueissame);
{
// Advance to next character.
var_offset.Bind(
assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
}
assembler->Goto(&loop);
assembler->Bind(&if_valueisnotsame);
assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value),
&if_less, &if_greater);
}
assembler->Bind(&if_done);
{
// All characters up to the min length are equal, decide based on
// string length.
Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
&if_lengthisequal, &if_lengthisnotequal);
assembler->Bind(&if_lengthisequal);
assembler->Goto(&if_equal);
assembler->Bind(&if_lengthisnotequal);
assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
&if_greater);
}
}
}
assembler->Bind(&if_notbothonebyteseqstrings);
{
// TODO(bmeurer): Add fast case support for flattened cons strings;
// also add support for two byte string relational comparisons.
switch (mode) {
case kLessThan:
assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
rhs);
break;
case kLessThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
lhs, rhs);
break;
case kGreaterThan:
assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
rhs);
break;
case kGreaterThanOrEqual:
assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
context, lhs, rhs);
break;
}
}
}
assembler->Bind(&if_less);
switch (mode) {
case kLessThan:
case kLessThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
case kGreaterThan:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(false));
break;
}
assembler->Bind(&if_equal);
switch (mode) {
case kLessThan:
case kGreaterThan:
assembler->Return(assembler->BooleanConstant(false));
break;
case kLessThanOrEqual:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
}
assembler->Bind(&if_greater);
switch (mode) {
case kLessThan:
case kLessThanOrEqual:
assembler->Return(assembler->BooleanConstant(false));
break;
case kGreaterThan:
case kGreaterThanOrEqual:
assembler->Return(assembler->BooleanConstant(true));
break;
}
}
void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
// Here's pseudo-code for the algorithm below in case of kDontNegateResult
// mode; for kNegateResult mode we properly negate the result.
//
// if (lhs == rhs) return true;
// if (lhs->length() != rhs->length()) return false;
// if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
// return false;
// }
// if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
// for (i = 0; i != lhs->length(); ++i) {
// if (lhs[i] != rhs[i]) return false;
// }
// return true;
// }
// return %StringEqual(lhs, rhs);
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
typedef CodeStubAssembler::Variable Variable;
Node* lhs = assembler->Parameter(0);
Node* rhs = assembler->Parameter(1);
Node* context = assembler->Parameter(2);
Label if_equal(assembler), if_notequal(assembler);
// Fast check to see if {lhs} and {rhs} refer to the same String object.
Label if_same(assembler), if_notsame(assembler);
assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
assembler->Bind(&if_same);
assembler->Goto(&if_equal);
assembler->Bind(&if_notsame);
{
// The {lhs} and {rhs} don't refer to the exact same String object.
// Load the length of {lhs} and {rhs}.
Node* lhs_length = assembler->LoadStringLength(lhs);
Node* rhs_length = assembler->LoadStringLength(rhs);
// Check if the lengths of {lhs} and {rhs} are equal.
Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
&if_lengthisequal, &if_lengthisnotequal);
assembler->Bind(&if_lengthisequal);
{
// Load instance types of {lhs} and {rhs}.
Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
// Combine the instance types into a single 16-bit value, so we can check
// both of them at once.
Node* both_instance_types = assembler->Word32Or(
lhs_instance_type,
assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
// Check if both {lhs} and {rhs} are internalized.
int const kBothInternalizedMask =
kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
int const kBothInternalizedTag =
kInternalizedTag | (kInternalizedTag << 8);
Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
assembler->Branch(assembler->Word32Equal(
assembler->Word32And(both_instance_types,
assembler->Int32Constant(
kBothInternalizedMask)),
assembler->Int32Constant(kBothInternalizedTag)),
&if_bothinternalized, &if_notbothinternalized);
assembler->Bind(&if_bothinternalized);
{
// Fast negative check for internalized-to-internalized equality.
assembler->Goto(&if_notequal);
}
assembler->Bind(&if_notbothinternalized);
{
// Check that both {lhs} and {rhs} are flat one-byte strings.
int const kBothSeqOneByteStringMask =
kStringEncodingMask | kStringRepresentationMask |
((kStringEncodingMask | kStringRepresentationMask) << 8);
int const kBothSeqOneByteStringTag =
kOneByteStringTag | kSeqStringTag |
((kOneByteStringTag | kSeqStringTag) << 8);
Label if_bothonebyteseqstrings(assembler),
if_notbothonebyteseqstrings(assembler);
assembler->Branch(
assembler->Word32Equal(
assembler->Word32And(
both_instance_types,
assembler->Int32Constant(kBothSeqOneByteStringMask)),
assembler->Int32Constant(kBothSeqOneByteStringTag)),
&if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
assembler->Bind(&if_bothonebyteseqstrings);
{
// Compute the effective offset of the first character.
Node* begin = assembler->IntPtrConstant(
SeqOneByteString::kHeaderSize - kHeapObjectTag);
// Compute the first offset after the string from the length.
Node* end =
assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
// Loop over the {lhs} and {rhs} strings to see if they are equal.
Variable var_offset(assembler, MachineType::PointerRepresentation());
Label loop(assembler, &var_offset);
var_offset.Bind(begin);
assembler->Goto(&loop);
assembler->Bind(&loop);
{
// Check if {offset} equals {end}.
Node* offset = var_offset.value();
Label if_done(assembler), if_notdone(assembler);
assembler->Branch(assembler->WordEqual(offset, end), &if_done,
&if_notdone);
assembler->Bind(&if_notdone);
{
// Load the next characters from {lhs} and {rhs}.
Node* lhs_value =
assembler->Load(MachineType::Uint8(), lhs, offset);
Node* rhs_value =
assembler->Load(MachineType::Uint8(), rhs, offset);
// Check if the characters match.
Label if_valueissame(assembler), if_valueisnotsame(assembler);
assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
&if_valueissame, &if_valueisnotsame);
assembler->Bind(&if_valueissame);
{
// Advance to next character.
var_offset.Bind(
assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
}
assembler->Goto(&loop);
assembler->Bind(&if_valueisnotsame);
assembler->Goto(&if_notequal);
}
assembler->Bind(&if_done);
assembler->Goto(&if_equal);
}
}
assembler->Bind(&if_notbothonebyteseqstrings);
{
// TODO(bmeurer): Add fast case support for flattened cons strings;
// also add support for two byte string equality checks.
Runtime::FunctionId function_id = (mode == kDontNegateResult)
? Runtime::kStringEqual
: Runtime::kStringNotEqual;
assembler->TailCallRuntime(function_id, context, lhs, rhs);
}
}
}
assembler->Bind(&if_lengthisnotequal);
{
// Mismatch in length of {lhs} and {rhs}, cannot be equal.
assembler->Goto(&if_notequal);
}
}
assembler->Bind(&if_equal);
assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
assembler->Bind(&if_notequal);
assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
}
} // namespace
void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const {
......@@ -4845,33 +4486,6 @@ compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler,
return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context);
}
void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
GenerateStringEqual(assembler, kDontNegateResult);
}
void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
GenerateStringEqual(assembler, kNegateResult);
}
void StringLessThanStub::GenerateAssembly(CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kLessThan);
}
void StringLessThanOrEqualStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
}
void StringGreaterThanStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kGreaterThan);
}
void StringGreaterThanOrEqualStub::GenerateAssembly(
CodeStubAssembler* assembler) const {
GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
}
void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const {
typedef CodeStubAssembler::Label Label;
typedef compiler::Node Node;
......
......@@ -148,12 +148,6 @@ class ObjectLiteral;
V(StoreScriptContextField) \
V(StrictEqual) \
V(StrictNotEqual) \
V(StringEqual) \
V(StringNotEqual) \
V(StringLessThan) \
V(StringLessThanOrEqual) \
V(StringGreaterThan) \
V(StringGreaterThanOrEqual) \
V(ToInteger) \
V(ToLength) \
V(HasProperty) \
......@@ -990,57 +984,6 @@ class StrictNotEqualStub final : public TurboFanCodeStub {
DEFINE_TURBOFAN_BINARY_OP_CODE_STUB(StrictNotEqual, TurboFanCodeStub);
};
class StringEqualStub final : public TurboFanCodeStub {
public:
explicit StringEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringEqual, TurboFanCodeStub);
};
class StringNotEqualStub final : public TurboFanCodeStub {
public:
explicit StringNotEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringNotEqual, TurboFanCodeStub);
};
class StringLessThanStub final : public TurboFanCodeStub {
public:
explicit StringLessThanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringLessThan, TurboFanCodeStub);
};
class StringLessThanOrEqualStub final : public TurboFanCodeStub {
public:
explicit StringLessThanOrEqualStub(Isolate* isolate)
: TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringLessThanOrEqual, TurboFanCodeStub);
};
class StringGreaterThanStub final : public TurboFanCodeStub {
public:
explicit StringGreaterThanStub(Isolate* isolate)
: TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringGreaterThan, TurboFanCodeStub);
};
class StringGreaterThanOrEqualStub final : public TurboFanCodeStub {
public:
explicit StringGreaterThanOrEqualStub(Isolate* isolate)
: TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(StringGreaterThanOrEqual, TurboFanCodeStub);
};
class ToIntegerStub final : public TurboFanCodeStub {
public:
explicit ToIntegerStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
......
......@@ -722,6 +722,15 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStringCharCodeAt:
state = LowerStringCharCodeAt(node, *effect, *control);
break;
case IrOpcode::kStringEqual:
state = LowerStringEqual(node, *effect, *control);
break;
case IrOpcode::kStringLessThan:
state = LowerStringLessThan(node, *effect, *control);
break;
case IrOpcode::kStringLessThanOrEqual:
state = LowerStringLessThanOrEqual(node, *effect, *control);
break;
case IrOpcode::kCheckFloat64Hole:
state = LowerCheckFloat64Hole(node, frame_state, *effect, *control);
break;
......@@ -2604,6 +2613,43 @@ EffectControlLinearizer::LowerStringFromCharCode(Node* node, Node* effect,
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringComparison(Callable const& callable,
Node* node, Node* effect,
Node* control) {
Operator::Properties properties = Operator::kEliminatable;
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
node->InsertInput(graph()->zone(), 0,
jsgraph()->HeapConstant(callable.code()));
node->AppendInput(graph()->zone(), jsgraph()->NoContextConstant());
node->AppendInput(graph()->zone(), effect);
NodeProperties::ChangeOp(node, common()->Call(desc));
return ValueEffectControl(node, node, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringEqual(Node* node, Node* effect,
Node* control) {
return LowerStringComparison(CodeFactory::StringEqual(isolate()), node,
effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringLessThan(Node* node, Node* effect,
Node* control) {
return LowerStringComparison(CodeFactory::StringLessThan(isolate()), node,
effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringLessThanOrEqual(Node* node, Node* effect,
Node* control) {
return LowerStringComparison(CodeFactory::StringLessThanOrEqual(isolate()),
node, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state,
Node* effect, Node* control) {
......
......@@ -12,6 +12,8 @@
namespace v8 {
namespace internal {
// Forward declarations.
class Callable;
class Zone;
namespace compiler {
......@@ -140,6 +142,11 @@ class EffectControlLinearizer {
Node* control);
ValueEffectControl LowerStringFromCharCode(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerStringEqual(Node* node, Node* effect, Node* control);
ValueEffectControl LowerStringLessThan(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerStringLessThanOrEqual(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerCheckFloat64Hole(Node* node, Node* frame_state,
Node* effect, Node* control);
ValueEffectControl LowerCheckTaggedHole(Node* node, Node* frame_state,
......@@ -179,6 +186,8 @@ class EffectControlLinearizer {
ValueEffectControl BuildCheckedHeapNumberOrOddballToFloat64(
CheckTaggedInputMode mode, Node* value, Node* frame_state, Node* effect,
Node* control);
ValueEffectControl LowerStringComparison(Callable const& callable, Node* node,
Node* effect, Node* control);
Node* ChangeInt32ToSmi(Node* value);
Node* ChangeUint32ToSmi(Node* value);
......
......@@ -622,14 +622,6 @@ PipelineCompilationJob::Status PipelineCompilationJob::PrepareJobImpl() {
if (!Compiler::EnsureDeoptimizationSupport(info())) return FAILED;
}
// TODO(mstarzinger): Hack to ensure that certain call descriptors are
// initialized on the main thread, since it is needed off-thread by the
// effect control linearizer.
CodeFactory::CopyFastSmiOrObjectElements(info()->isolate());
CodeFactory::GrowFastDoubleElements(info()->isolate());
CodeFactory::GrowFastSmiOrObjectElements(info()->isolate());
CodeFactory::ToNumber(info()->isolate());
linkage_ = new (&zone_) Linkage(Linkage::ComputeIncoming(&zone_, info()));
if (!pipeline_.CreateGraph()) {
......
......@@ -2040,62 +2040,11 @@ class RepresentationSelector {
}
return;
}
case IrOpcode::kStringEqual: {
VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
if (lower()) {
// StringEqual(x, y) => Call(StringEqualStub, x, y, no-context)
Operator::Properties properties =
Operator::kCommutative | Operator::kEliminatable;
Callable callable = CodeFactory::StringEqual(jsgraph_->isolate());
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
flags, properties);
node->InsertInput(jsgraph_->zone(), 0,
jsgraph_->HeapConstant(callable.code()));
node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
}
return;
}
case IrOpcode::kStringLessThan: {
VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
if (lower()) {
// StringLessThan(x, y) => Call(StringLessThanStub, x, y, no-context)
Operator::Properties properties = Operator::kEliminatable;
Callable callable = CodeFactory::StringLessThan(jsgraph_->isolate());
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
flags, properties);
node->InsertInput(jsgraph_->zone(), 0,
jsgraph_->HeapConstant(callable.code()));
node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
}
return;
}
case IrOpcode::kStringEqual:
case IrOpcode::kStringLessThan:
case IrOpcode::kStringLessThanOrEqual: {
VisitBinop(node, UseInfo::AnyTagged(), MachineRepresentation::kTagged);
if (lower()) {
// StringLessThanOrEqual(x, y)
// => Call(StringLessThanOrEqualStub, x, y, no-context)
Operator::Properties properties = Operator::kEliminatable;
Callable callable =
CodeFactory::StringLessThanOrEqual(jsgraph_->isolate());
CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
CallDescriptor* desc = Linkage::GetStubCallDescriptor(
jsgraph_->isolate(), jsgraph_->zone(), callable.descriptor(), 0,
flags, properties);
node->InsertInput(jsgraph_->zone(), 0,
jsgraph_->HeapConstant(callable.code()));
node->AppendInput(jsgraph_->zone(), jsgraph_->NoContextConstant());
node->AppendInput(jsgraph_->zone(), jsgraph_->graph()->start());
NodeProperties::ChangeOp(node, jsgraph_->common()->Call(desc));
}
return;
return VisitBinop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTagged);
}
case IrOpcode::kStringCharCodeAt: {
VisitBinop(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
......
......@@ -27,6 +27,7 @@
#include "src/external-reference-table.h"
#include "src/frames-inl.h"
#include "src/ic/stub-cache.h"
#include "src/interface-descriptors.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h"
#include "src/libsampler/sampler.h"
......@@ -2390,6 +2391,12 @@ bool Isolate::Init(Deserializer* des) {
return false;
}
// Initialize the interface descriptors ahead of time.
#define INTERFACE_DESCRIPTOR(V) \
{ V##Descriptor(this); }
INTERFACE_DESCRIPTOR_LIST(INTERFACE_DESCRIPTOR)
#undef INTERFACE_DESCRIPTOR
deoptimizer_data_ = new DeoptimizerData(heap()->memory_allocator());
const bool create_heap_objects = (des == NULL);
......
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