Commit 62bc168d authored by bmeurer's avatar bmeurer Committed by Commit bot

[compiler] Initial TurboFan code stubs for abstract relational comparison.

This adds new code stubs for abstract relational comparison,
namely LessThanStub, LessThanOrEqualStub, GreaterThanStub and
GreaterThanOrEqualStub, and hooks them up for Ignition and TurboFan.
These stubs implement the full compare operation without any
unpredictable bailouts. Currently they still go to C++ for string
comparisons, and also use the %ToPrimitive_Number runtime entry, as
we still lack a stub for the ToPrimitive operation. These issues
will be addressed separately in follow-up CLs.

Drive-by-fix: Add support for deferred code in the RawMachineAssembler
and CodeStubAssembler. A block can be marked as deferred by marking its
Label as deferred, which will then make the register allocator penalize
this block and prefer better register assignments for the other blocks.

R=epertoso@chromium.org

Review URL: https://codereview.chromium.org/1759133002

Cr-Commit-Position: refs/heads/master@{#34463}
parent d61b8cee
......@@ -194,6 +194,30 @@ Callable CodeFactory::RegExpExec(Isolate* isolate) {
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::LessThan(Isolate* isolate) {
LessThanStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::LessThanOrEqual(Isolate* isolate) {
LessThanOrEqualStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::GreaterThan(Isolate* isolate) {
GreaterThanStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::GreaterThanOrEqual(Isolate* isolate) {
GreaterThanOrEqualStub stub(isolate);
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
}
// static
Callable CodeFactory::StrictEqual(Isolate* isolate) {
StrictEqualStub stub(isolate);
......
......@@ -75,6 +75,10 @@ class CodeFactory final {
static Callable RegExpConstructResult(Isolate* isolate);
static Callable RegExpExec(Isolate* isolate);
static Callable LessThan(Isolate* isolate);
static Callable LessThanOrEqual(Isolate* isolate);
static Callable GreaterThan(Isolate* isolate);
static Callable GreaterThanOrEqual(Isolate* isolate);
static Callable StrictEqual(Isolate* isolate);
static Callable StrictNotEqual(Isolate* isolate);
......
This diff is collapsed.
......@@ -101,6 +101,10 @@ namespace internal {
V(AllocateHeapNumber) \
V(AllocateMutableHeapNumber) \
V(StringLength) \
V(LessThan) \
V(LessThanOrEqual) \
V(GreaterThan) \
V(GreaterThanOrEqual) \
V(StrictEqual) \
V(StrictNotEqual) \
V(StringEqual) \
......@@ -351,11 +355,10 @@ class CodeStub BASE_EMBEDDED {
Handle<Code> GenerateCode() override; \
DEFINE_CODE_STUB(NAME, SUPER)
#define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER) \
public: \
CallInterfaceDescriptor GetCallInterfaceDescriptor() const override { \
return DESC##Descriptor(isolate()); \
}; \
#define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER) \
public: \
void GenerateAssembly(compiler::CodeStubAssembler* assembler) \
const override; \
DEFINE_CODE_STUB(NAME, SUPER)
#define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \
......@@ -629,60 +632,81 @@ class StringLengthStub : public TurboFanCodeStub {
InlineCacheState GetICState() const override { return MONOMORPHIC; }
ExtraICState GetExtraICState() const override { return Code::LOAD_IC; }
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const override;
DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadWithVector);
DEFINE_CODE_STUB(StringLength, TurboFanCodeStub);
DEFINE_TURBOFAN_CODE_STUB(StringLength, TurboFanCodeStub);
};
class LessThanStub final : public TurboFanCodeStub {
public:
explicit LessThanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(LessThan, TurboFanCodeStub);
};
class LessThanOrEqualStub final : public TurboFanCodeStub {
public:
explicit LessThanOrEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(LessThanOrEqual, TurboFanCodeStub);
};
class GreaterThanStub final : public TurboFanCodeStub {
public:
explicit GreaterThanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(GreaterThan, TurboFanCodeStub);
};
class GreaterThanOrEqualStub final : public TurboFanCodeStub {
public:
explicit GreaterThanOrEqualStub(Isolate* isolate)
: TurboFanCodeStub(isolate) {}
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_TURBOFAN_CODE_STUB(GreaterThanOrEqual, TurboFanCodeStub);
};
class StrictEqualStub final : public TurboFanCodeStub {
public:
explicit StrictEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_CODE_STUB(StrictEqual, TurboFanCodeStub);
DEFINE_TURBOFAN_CODE_STUB(StrictEqual, TurboFanCodeStub);
};
class StrictNotEqualStub final : public TurboFanCodeStub {
public:
explicit StrictNotEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_CODE_STUB(StrictNotEqual, TurboFanCodeStub);
DEFINE_TURBOFAN_CODE_STUB(StrictNotEqual, TurboFanCodeStub);
};
class StringEqualStub final : public TurboFanCodeStub {
public:
explicit StringEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_CODE_STUB(StringEqual, TurboFanCodeStub);
DEFINE_TURBOFAN_CODE_STUB(StringEqual, TurboFanCodeStub);
};
class StringNotEqualStub final : public TurboFanCodeStub {
public:
explicit StringNotEqualStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(Compare);
DEFINE_CODE_STUB(StringNotEqual, TurboFanCodeStub);
DEFINE_TURBOFAN_CODE_STUB(StringNotEqual, TurboFanCodeStub);
};
class ToBooleanStub final : public TurboFanCodeStub {
public:
explicit ToBooleanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
void GenerateAssembly(compiler::CodeStubAssembler* assembler) const final;
DEFINE_CALL_INTERFACE_DESCRIPTOR(ToBoolean);
DEFINE_CODE_STUB(ToBoolean, TurboFanCodeStub);
DEFINE_TURBOFAN_CODE_STUB(ToBoolean, TurboFanCodeStub);
};
enum StringAddFlags {
......
......@@ -163,6 +163,14 @@ Node* CodeStubAssembler::SmiAdd(Node* a, Node* b) { return IntPtrAdd(a, b); }
Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); }
Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) {
return IntPtrLessThan(a, b);
}
Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) {
return IntPtrLessThanOrEqual(a, b);
}
#define DEFINE_CODE_STUB_ASSEMBER_BINARY_OP(name) \
Node* CodeStubAssembler::name(Node* a, Node* b) { \
return raw_assembler_->name(a, b); \
......@@ -416,6 +424,27 @@ Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift,
raw_assembler_->Int32Constant(shift));
}
void CodeStubAssembler::BranchIfSmiLessThan(Node* a, Node* b, Label* if_true,
Label* if_false) {
Label if_lessthan(this), if_notlessthan(this);
Branch(SmiLessThan(a, b), &if_lessthan, &if_notlessthan);
Bind(&if_lessthan);
Goto(if_true);
Bind(&if_notlessthan);
Goto(if_false);
}
void CodeStubAssembler::BranchIfSmiLessThanOrEqual(Node* a, Node* b,
Label* if_true,
Label* if_false) {
Label if_lessthanorequal(this), if_notlessthanorequal(this);
Branch(SmiLessThanOrEqual(a, b), &if_lessthanorequal, &if_notlessthanorequal);
Bind(&if_lessthanorequal);
Goto(if_true);
Bind(&if_notlessthanorequal);
Goto(if_false);
}
void CodeStubAssembler::BranchIfFloat64Equal(Node* a, Node* b, Label* if_true,
Label* if_false) {
Label if_equal(this), if_notequal(this);
......@@ -426,6 +455,52 @@ void CodeStubAssembler::BranchIfFloat64Equal(Node* a, Node* b, Label* if_true,
Goto(if_false);
}
void CodeStubAssembler::BranchIfFloat64LessThan(Node* a, Node* b,
Label* if_true,
Label* if_false) {
Label if_lessthan(this), if_notlessthan(this);
Branch(Float64LessThan(a, b), &if_lessthan, &if_notlessthan);
Bind(&if_lessthan);
Goto(if_true);
Bind(&if_notlessthan);
Goto(if_false);
}
void CodeStubAssembler::BranchIfFloat64LessThanOrEqual(Node* a, Node* b,
Label* if_true,
Label* if_false) {
Label if_lessthanorequal(this), if_notlessthanorequal(this);
Branch(Float64LessThanOrEqual(a, b), &if_lessthanorequal,
&if_notlessthanorequal);
Bind(&if_lessthanorequal);
Goto(if_true);
Bind(&if_notlessthanorequal);
Goto(if_false);
}
void CodeStubAssembler::BranchIfFloat64GreaterThan(Node* a, Node* b,
Label* if_true,
Label* if_false) {
Label if_greaterthan(this), if_notgreaterthan(this);
Branch(Float64GreaterThan(a, b), &if_greaterthan, &if_notgreaterthan);
Bind(&if_greaterthan);
Goto(if_true);
Bind(&if_notgreaterthan);
Goto(if_false);
}
void CodeStubAssembler::BranchIfFloat64GreaterThanOrEqual(Node* a, Node* b,
Label* if_true,
Label* if_false) {
Label if_greaterthanorequal(this), if_notgreaterthanorequal(this);
Branch(Float64GreaterThanOrEqual(a, b), &if_greaterthanorequal,
&if_notgreaterthanorequal);
Bind(&if_greaterthanorequal);
Goto(if_true);
Bind(&if_notgreaterthanorequal);
Goto(if_false);
}
Node* CodeStubAssembler::CallN(CallDescriptor* descriptor, Node* code_target,
Node** args) {
CallPrologue();
......@@ -515,6 +590,12 @@ Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id,
context);
}
Node* CodeStubAssembler::CallStub(Callable const& callable, Node* context,
Node* arg1, size_t result_size) {
Node* target = HeapConstant(callable.code());
return CallStub(callable.descriptor(), target, context, arg1, result_size);
}
Node* CodeStubAssembler::CallStub(const CallInterfaceDescriptor& descriptor,
Node* target, Node* context, Node* arg1,
size_t result_size) {
......@@ -709,27 +790,20 @@ bool CodeStubAssembler::Variable::IsBound() const {
return impl_->value_ != nullptr;
}
CodeStubAssembler::Label::Label(CodeStubAssembler* assembler)
: bound_(false), merge_count_(0), assembler_(assembler), label_(nullptr) {
void* buffer = assembler->zone()->New(sizeof(RawMachineLabel));
label_ = new (buffer) RawMachineLabel();
}
CodeStubAssembler::Label::Label(CodeStubAssembler* assembler,
int merged_value_count,
CodeStubAssembler::Variable** merged_variables)
CodeStubAssembler::Variable** merged_variables,
CodeStubAssembler::Label::Type type)
: bound_(false), merge_count_(0), assembler_(assembler), label_(nullptr) {
void* buffer = assembler->zone()->New(sizeof(RawMachineLabel));
label_ = new (buffer) RawMachineLabel();
label_ = new (buffer)
RawMachineLabel(type == kDeferred ? RawMachineLabel::kDeferred
: RawMachineLabel::kNonDeferred);
for (int i = 0; i < merged_value_count; ++i) {
variable_phis_[merged_variables[i]->impl_] = nullptr;
}
}
CodeStubAssembler::Label::Label(CodeStubAssembler* assembler,
CodeStubAssembler::Variable* merged_variable)
: CodeStubAssembler::Label(assembler, 1, &merged_variable) {}
void CodeStubAssembler::Label::MergeVariables() {
++merge_count_;
for (auto var : assembler_->variables_) {
......@@ -760,16 +834,17 @@ void CodeStubAssembler::Label::MergeVariables() {
assembler_->raw_assembler_->AppendPhiInput(phi->second, node);
} else {
auto i = variable_merges_.find(var);
USE(i);
// If the following assert fires, then you've declared a variable that
// has the same bound value along all paths up until the point you bound
// this label, but then later merged a path with a new value for the
// variable after the label bind (it's not possible to add phis to the
// bound label after the fact, just make sure to list the variable in
// the label's constructor's list of merged variables).
DCHECK(find_if(i->second.begin(), i->second.end(),
[node](Node* e) -> bool { return node != e; }) ==
i->second.end());
if (i != variable_merges_.end()) {
// If the following assert fires, then you've declared a variable that
// has the same bound value along all paths up until the point you
// bound this label, but then later merged a path with a new value for
// the variable after the label bind (it's not possible to add phis to
// the bound label after the fact, just make sure to list the variable
// in the label's constructor's list of merged variables).
DCHECK(find_if(i->second.begin(), i->second.end(),
[node](Node* e) -> bool { return node != e; }) ==
i->second.end());
}
}
}
}
......
......@@ -39,13 +39,17 @@ class Schedule;
V(Float64Equal) \
V(Float64LessThan) \
V(Float64LessThanOrEqual) \
V(Float64GreaterThan) \
V(Float64GreaterThanOrEqual) \
V(IntPtrAdd) \
V(IntPtrSub) \
V(Int32Add) \
V(Int32Sub) \
V(Int32Mul) \
V(Int32GreaterThan) \
V(Int32GreaterThanOrEqual) \
V(Int32LessThan) \
V(Int32LessThanOrEqual) \
V(WordEqual) \
V(WordNotEqual) \
V(WordOr) \
......@@ -72,6 +76,8 @@ class Schedule;
V(Word64Shr) \
V(Word64Sar) \
V(Word64Ror) \
V(IntPtrLessThan) \
V(IntPtrLessThanOrEqual) \
V(UintPtrGreaterThanOrEqual)
#define CODE_STUB_ASSEMBLER_UNARY_OP_LIST(V) \
......@@ -202,6 +208,9 @@ class CodeStubAssembler {
Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context,
Node* arg1, Node* arg2, Node* arg3, Node* arg4);
Node* CallStub(Callable const& callable, Node* context, Node* arg1,
size_t result_size = 1);
Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
Node* context, Node* arg1, size_t result_size = 1);
Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
......@@ -242,6 +251,8 @@ class CodeStubAssembler {
// Smi operations.
Node* SmiAdd(Node* a, Node* b);
Node* SmiEqual(Node* a, Node* b);
Node* SmiLessThan(Node* a, Node* b);
Node* SmiLessThanOrEqual(Node* a, Node* b);
// Load a value from the root array.
Node* LoadRoot(Heap::RootListIndex root_index);
......@@ -281,18 +292,31 @@ class CodeStubAssembler {
// Branching helpers.
// TODO(danno): Can we be more cleverish wrt. edge-split?
void BranchIfSmiLessThan(Node* a, Node* b, Label* if_true, Label* if_false);
void BranchIfSmiLessThanOrEqual(Node* a, Node* b, Label* if_true,
Label* if_false);
void BranchIfFloat64Equal(Node* a, Node* b, Label* if_true, Label* if_false);
void BranchIfFloat64LessThan(Node* a, Node* b, Label* if_true,
Label* if_false);
void BranchIfFloat64LessThanOrEqual(Node* a, Node* b, Label* if_true,
Label* if_false);
void BranchIfFloat64GreaterThan(Node* a, Node* b, Label* if_true,
Label* if_false);
void BranchIfFloat64GreaterThanOrEqual(Node* a, Node* b, Label* if_true,
Label* if_false);
void BranchIfFloat64IsNaN(Node* value, Label* if_true, Label* if_false) {
BranchIfFloat64Equal(value, value, if_false, if_true);
}
protected:
// Protected helpers which delegate to RawMachineAssembler.
Graph* graph() const;
// Helpers which delegate to RawMachineAssembler.
Factory* factory() const;
Isolate* isolate() const;
Zone* zone() const;
protected:
// Protected helpers which delegate to RawMachineAssembler.
Graph* graph() const;
// Enables subclasses to perform operations before and after a call.
virtual void CallPrologue();
virtual void CallEpilogue();
......@@ -323,11 +347,21 @@ DEFINE_OPERATORS_FOR_FLAGS(CodeStubAssembler::AllocationFlags);
class CodeStubAssembler::Label {
public:
explicit Label(CodeStubAssembler* assembler);
Label(CodeStubAssembler* assembler, int merged_variable_count,
CodeStubAssembler::Variable** merged_variables);
enum Type { kDeferred, kNonDeferred };
explicit Label(CodeStubAssembler* assembler,
CodeStubAssembler::Label::Type type =
CodeStubAssembler::Label::kNonDeferred)
: CodeStubAssembler::Label(assembler, 0, nullptr, type) {}
Label(CodeStubAssembler* assembler,
CodeStubAssembler::Variable* merged_variable);
CodeStubAssembler::Variable* merged_variable,
CodeStubAssembler::Label::Type type =
CodeStubAssembler::Label::kNonDeferred)
: CodeStubAssembler::Label(assembler, 1, &merged_variable, type) {}
Label(CodeStubAssembler* assembler, int merged_variable_count,
CodeStubAssembler::Variable** merged_variables,
CodeStubAssembler::Label::Type type =
CodeStubAssembler::Label::kNonDeferred);
~Label() {}
private:
......
......@@ -89,10 +89,6 @@ REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
}
REPLACE_RUNTIME_CALL(JSEqual, Runtime::kEqual)
REPLACE_RUNTIME_CALL(JSNotEqual, Runtime::kNotEqual)
REPLACE_RUNTIME_CALL(JSLessThan, Runtime::kLessThan)
REPLACE_RUNTIME_CALL(JSGreaterThan, Runtime::kGreaterThan)
REPLACE_RUNTIME_CALL(JSLessThanOrEqual, Runtime::kLessThanOrEqual)
REPLACE_RUNTIME_CALL(JSGreaterThanOrEqual, Runtime::kGreaterThanOrEqual)
REPLACE_RUNTIME_CALL(JSCreateWithContext, Runtime::kPushWithContext)
REPLACE_RUNTIME_CALL(JSCreateModuleContext, Runtime::kPushModuleContext)
REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
......@@ -104,6 +100,10 @@ REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
Callable callable = CodeFactory::Name(isolate()); \
ReplaceWithStubCall(node, callable, flags); \
}
REPLACE_STUB_CALL(LessThan)
REPLACE_STUB_CALL(LessThanOrEqual)
REPLACE_STUB_CALL(GreaterThan)
REPLACE_STUB_CALL(GreaterThanOrEqual)
REPLACE_STUB_CALL(StrictEqual)
REPLACE_STUB_CALL(StrictNotEqual)
#undef REPLACE_STUB_CALL
......
......@@ -428,6 +428,7 @@ void RawMachineAssembler::Bind(RawMachineLabel* label) {
DCHECK(!label->bound_);
label->bound_ = true;
current_block_ = EnsureBlock(label);
current_block_->set_deferred(label->deferred_);
}
......@@ -480,11 +481,6 @@ Node* RawMachineAssembler::MakeNode(const Operator* op, int input_count,
return graph()->NewNodeUnchecked(op, input_count, inputs);
}
RawMachineLabel::RawMachineLabel()
: block_(nullptr), used_(false), bound_(false) {}
RawMachineLabel::~RawMachineLabel() { DCHECK(bound_ || !used_); }
} // namespace compiler
......
......@@ -700,13 +700,17 @@ class RawMachineAssembler {
class RawMachineLabel final {
public:
RawMachineLabel();
enum Type { kDeferred, kNonDeferred };
explicit RawMachineLabel(Type type = kNonDeferred)
: deferred_(type == kDeferred) {}
~RawMachineLabel();
private:
BasicBlock* block_;
bool used_;
bool bound_;
BasicBlock* block_ = nullptr;
bool used_ = false;
bool bound_ = false;
bool deferred_;
friend class RawMachineAssembler;
DISALLOW_COPY_AND_ASSIGN(RawMachineLabel);
};
......
......@@ -1205,7 +1205,7 @@ void Interpreter::DoTestNotEqualStrict(InterpreterAssembler* assembler) {
//
// Test if the value in the <src> register is less than the accumulator.
void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kLessThan, assembler);
DoBinaryOp(CodeFactory::LessThan(isolate_), assembler);
}
......@@ -1213,7 +1213,7 @@ void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) {
//
// Test if the value in the <src> register is greater than the accumulator.
void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kGreaterThan, assembler);
DoBinaryOp(CodeFactory::GreaterThan(isolate_), assembler);
}
......@@ -1222,7 +1222,7 @@ void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) {
// Test if the value in the <src> register is less than or equal to the
// accumulator.
void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kLessThanOrEqual, assembler);
DoBinaryOp(CodeFactory::LessThanOrEqual(isolate_), assembler);
}
......@@ -1231,7 +1231,7 @@ void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) {
// Test if the value in the <src> register is greater than or equal to the
// accumulator.
void Interpreter::DoTestGreaterThanOrEqual(InterpreterAssembler* assembler) {
DoBinaryOp(Runtime::kGreaterThanOrEqual, assembler);
DoBinaryOp(CodeFactory::GreaterThanOrEqual(isolate_), assembler);
}
......
......@@ -1145,6 +1145,78 @@ RUNTIME_FUNCTION(Runtime_NewString) {
return *result;
}
RUNTIME_FUNCTION(Runtime_StringLessThan) {
HandleScope handle_scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
switch (String::Compare(x, y)) {
case ComparisonResult::kLessThan:
return isolate->heap()->true_value();
case ComparisonResult::kEqual:
case ComparisonResult::kGreaterThan:
return isolate->heap()->false_value();
case ComparisonResult::kUndefined:
break;
}
UNREACHABLE();
return Smi::FromInt(0);
}
RUNTIME_FUNCTION(Runtime_StringLessThanOrEqual) {
HandleScope handle_scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
switch (String::Compare(x, y)) {
case ComparisonResult::kEqual:
case ComparisonResult::kLessThan:
return isolate->heap()->true_value();
case ComparisonResult::kGreaterThan:
return isolate->heap()->false_value();
case ComparisonResult::kUndefined:
break;
}
UNREACHABLE();
return Smi::FromInt(0);
}
RUNTIME_FUNCTION(Runtime_StringGreaterThan) {
HandleScope handle_scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
switch (String::Compare(x, y)) {
case ComparisonResult::kGreaterThan:
return isolate->heap()->true_value();
case ComparisonResult::kEqual:
case ComparisonResult::kLessThan:
return isolate->heap()->false_value();
case ComparisonResult::kUndefined:
break;
}
UNREACHABLE();
return Smi::FromInt(0);
}
RUNTIME_FUNCTION(Runtime_StringGreaterThanOrEqual) {
HandleScope handle_scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(String, x, 0);
CONVERT_ARG_HANDLE_CHECKED(String, y, 1);
switch (String::Compare(x, y)) {
case ComparisonResult::kEqual:
case ComparisonResult::kGreaterThan:
return isolate->heap()->true_value();
case ComparisonResult::kLessThan:
return isolate->heap()->false_value();
case ComparisonResult::kUndefined:
break;
}
UNREACHABLE();
return Smi::FromInt(0);
}
RUNTIME_FUNCTION(Runtime_StringEqual) {
HandleScope handle_scope(isolate);
DCHECK_EQ(2, args.length());
......
......@@ -862,6 +862,10 @@ namespace internal {
F(StringTrim, 3, 1) \
F(TruncateString, 2, 1) \
F(NewString, 2, 1) \
F(StringLessThan, 2, 1) \
F(StringLessThanOrEqual, 2, 1) \
F(StringGreaterThan, 2, 1) \
F(StringGreaterThanOrEqual, 2, 1) \
F(StringEqual, 2, 1) \
F(StringNotEqual, 2, 1) \
F(FlattenString, 1, 1) \
......
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