[stubs] Introduce AddStub and SubtractStub.
This adds two new stubs, AddStub and SubtractStub, for the plus and the minus operators, and hooks them up with TurboFan and Ignition. Especially the addition case is very heavy and we might want to look into splitting that up further into specialized stubs (similar to what we did with ToNumberStub recently). R=epertoso@chromium.org Review URL: https://codereview.chromium.org/1823083002 Cr-Commit-Position: refs/heads/master@{#34994}
This commit is contained in:
parent
890f3dd7c5
commit
0bedf6f061
@ -206,6 +206,18 @@ Callable CodeFactory::RegExpExec(Isolate* isolate) {
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::Add(Isolate* isolate) {
|
||||
AddStub stub(isolate);
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::Subtract(Isolate* isolate) {
|
||||
SubtractStub stub(isolate);
|
||||
return Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor());
|
||||
}
|
||||
|
||||
// static
|
||||
Callable CodeFactory::LessThan(Isolate* isolate) {
|
||||
LessThanStub stub(isolate);
|
||||
|
@ -79,6 +79,8 @@ class CodeFactory final {
|
||||
static Callable RegExpConstructResult(Isolate* isolate);
|
||||
static Callable RegExpExec(Isolate* isolate);
|
||||
|
||||
static Callable Add(Isolate* isolate);
|
||||
static Callable Subtract(Isolate* isolate);
|
||||
static Callable LessThan(Isolate* isolate);
|
||||
static Callable LessThanOrEqual(Isolate* isolate);
|
||||
static Callable GreaterThan(Isolate* isolate);
|
||||
|
@ -515,6 +515,540 @@ void StringLengthStub::GenerateAssembly(
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
void AddStub::GenerateAssembly(compiler::CodeStubAssembler* assembler) const {
|
||||
typedef compiler::CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
typedef compiler::CodeStubAssembler::Variable Variable;
|
||||
|
||||
Node* context = assembler->Parameter(2);
|
||||
|
||||
// Shared entry for floating point addition.
|
||||
Label do_fadd(assembler);
|
||||
Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64),
|
||||
var_fadd_rhs(assembler, MachineRepresentation::kFloat64);
|
||||
|
||||
// We might need to loop several times due to ToPrimitive, ToString and/or
|
||||
// ToNumber conversions.
|
||||
Variable var_lhs(assembler, MachineRepresentation::kTagged),
|
||||
var_rhs(assembler, MachineRepresentation::kTagged);
|
||||
Variable* loop_vars[2] = {&var_lhs, &var_rhs};
|
||||
Label loop(assembler, 2, loop_vars);
|
||||
var_lhs.Bind(assembler->Parameter(0));
|
||||
var_rhs.Bind(assembler->Parameter(1));
|
||||
assembler->Goto(&loop);
|
||||
assembler->Bind(&loop);
|
||||
{
|
||||
// Load the current {lhs} and {rhs} values.
|
||||
Node* lhs = var_lhs.value();
|
||||
Node* rhs = var_rhs.value();
|
||||
|
||||
// Check if the {lhs} is a Smi or a HeapObject.
|
||||
Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_lhsissmi);
|
||||
{
|
||||
// Check if the {rhs} is also a Smi.
|
||||
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
|
||||
&if_rhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_rhsissmi);
|
||||
{
|
||||
// TODO(bmeurer): Properly fuse Int64AddWithOverflow on x64
|
||||
Node* pair = assembler->SmiAddWithOverflow(lhs, rhs);
|
||||
Node* result = assembler->Projection(0, pair);
|
||||
Node* overflow = assembler->Projection(1, pair);
|
||||
|
||||
Label if_overflow(assembler), if_notoverflow(assembler);
|
||||
assembler->Branch(overflow, &if_overflow, &if_notoverflow);
|
||||
|
||||
assembler->Bind(&if_overflow);
|
||||
{
|
||||
var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
|
||||
var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
|
||||
assembler->Goto(&do_fadd);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_notoverflow);
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotsmi);
|
||||
{
|
||||
// Load the map of {rhs}.
|
||||
Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
|
||||
|
||||
// Check if the {rhs} is a HeapNumber.
|
||||
Label if_rhsisnumber(assembler),
|
||||
if_rhsisnotnumber(assembler, Label::kDeferred);
|
||||
Node* number_map = assembler->HeapNumberMapConstant();
|
||||
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
|
||||
&if_rhsisnumber, &if_rhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_rhsisnumber);
|
||||
{
|
||||
var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
|
||||
var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
|
||||
assembler->Goto(&do_fadd);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotnumber);
|
||||
{
|
||||
// Load the instance type of {rhs}.
|
||||
Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
|
||||
|
||||
// Check if the {rhs} is a String.
|
||||
Label if_rhsisstring(assembler, Label::kDeferred),
|
||||
if_rhsisnotstring(assembler, Label::kDeferred);
|
||||
assembler->Branch(assembler->Int32LessThan(
|
||||
rhs_instance_type,
|
||||
assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
|
||||
&if_rhsisstring, &if_rhsisnotstring);
|
||||
|
||||
assembler->Bind(&if_rhsisstring);
|
||||
{
|
||||
// Convert {lhs}, which is a Smi, to a String and concatenate the
|
||||
// resulting string with the String {rhs}.
|
||||
Callable callable = CodeFactory::StringAdd(
|
||||
assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
|
||||
assembler->TailCallStub(callable, context, lhs, rhs);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotstring);
|
||||
{
|
||||
// Check if {rhs} is a JSReceiver.
|
||||
Label if_rhsisreceiver(assembler, Label::kDeferred),
|
||||
if_rhsisnotreceiver(assembler, Label::kDeferred);
|
||||
assembler->Branch(
|
||||
assembler->Int32LessThanOrEqual(
|
||||
assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
|
||||
rhs_instance_type),
|
||||
&if_rhsisreceiver, &if_rhsisnotreceiver);
|
||||
|
||||
assembler->Bind(&if_rhsisreceiver);
|
||||
{
|
||||
// Convert {rhs} to a primitive first passing no hint.
|
||||
// TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
|
||||
var_rhs.Bind(
|
||||
assembler->CallRuntime(Runtime::kToPrimitive, context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotreceiver);
|
||||
{
|
||||
// Convert {rhs} to a Number first.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotsmi);
|
||||
{
|
||||
// Load the map and instance type of {lhs}.
|
||||
Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
|
||||
|
||||
// Check if {lhs} is a String.
|
||||
Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
|
||||
assembler->Branch(assembler->Int32LessThan(
|
||||
lhs_instance_type,
|
||||
assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
|
||||
&if_lhsisstring, &if_lhsisnotstring);
|
||||
|
||||
assembler->Bind(&if_lhsisstring);
|
||||
{
|
||||
// Convert {rhs} to a String (using the sequence of ToPrimitive with
|
||||
// no hint followed by ToString) and concatenate the strings.
|
||||
Callable callable = CodeFactory::StringAdd(
|
||||
assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED);
|
||||
assembler->TailCallStub(callable, context, lhs, rhs);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotstring);
|
||||
{
|
||||
// Check if {rhs} is a Smi.
|
||||
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
|
||||
&if_rhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_rhsissmi);
|
||||
{
|
||||
// Check if {lhs} is a Number.
|
||||
Label if_lhsisnumber(assembler),
|
||||
if_lhsisnotnumber(assembler, Label::kDeferred);
|
||||
assembler->Branch(assembler->Word32Equal(
|
||||
lhs_instance_type,
|
||||
assembler->Int32Constant(HEAP_NUMBER_TYPE)),
|
||||
&if_lhsisnumber, &if_lhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_lhsisnumber);
|
||||
{
|
||||
// The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them.
|
||||
var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
|
||||
var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
|
||||
assembler->Goto(&do_fadd);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotnumber);
|
||||
{
|
||||
// The {lhs} is neither a Number nor a String, and the {rhs} is a
|
||||
// Smi.
|
||||
Label if_lhsisreceiver(assembler, Label::kDeferred),
|
||||
if_lhsisnotreceiver(assembler, Label::kDeferred);
|
||||
assembler->Branch(
|
||||
assembler->Int32LessThanOrEqual(
|
||||
assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
|
||||
lhs_instance_type),
|
||||
&if_lhsisreceiver, &if_lhsisnotreceiver);
|
||||
|
||||
assembler->Bind(&if_lhsisreceiver);
|
||||
{
|
||||
// Convert {lhs} to a primitive first passing no hint.
|
||||
// TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
|
||||
var_lhs.Bind(
|
||||
assembler->CallRuntime(Runtime::kToPrimitive, context, lhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotreceiver);
|
||||
{
|
||||
// Convert {lhs} to a Number first.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_lhs.Bind(assembler->CallStub(callable, context, lhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotsmi);
|
||||
{
|
||||
// Load the instance type of {rhs}.
|
||||
Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
|
||||
|
||||
// Check if {rhs} is a String.
|
||||
Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
|
||||
assembler->Branch(assembler->Int32LessThan(
|
||||
rhs_instance_type,
|
||||
assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
|
||||
&if_rhsisstring, &if_rhsisnotstring);
|
||||
|
||||
assembler->Bind(&if_rhsisstring);
|
||||
{
|
||||
// Convert {lhs} to a String (using the sequence of ToPrimitive with
|
||||
// no hint followed by ToString) and concatenate the strings.
|
||||
Callable callable = CodeFactory::StringAdd(
|
||||
assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
|
||||
assembler->TailCallStub(callable, context, lhs, rhs);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotstring);
|
||||
{
|
||||
// Check if {lhs} is a HeapNumber.
|
||||
Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
|
||||
assembler->Branch(assembler->Word32Equal(
|
||||
lhs_instance_type,
|
||||
assembler->Int32Constant(HEAP_NUMBER_TYPE)),
|
||||
&if_lhsisnumber, &if_lhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_lhsisnumber);
|
||||
{
|
||||
// Check if {rhs} is also a HeapNumber.
|
||||
Label if_rhsisnumber(assembler),
|
||||
if_rhsisnotnumber(assembler, Label::kDeferred);
|
||||
assembler->Branch(assembler->Word32Equal(
|
||||
rhs_instance_type,
|
||||
assembler->Int32Constant(HEAP_NUMBER_TYPE)),
|
||||
&if_rhsisnumber, &if_rhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_rhsisnumber);
|
||||
{
|
||||
// Perform a floating point addition.
|
||||
var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
|
||||
var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
|
||||
assembler->Goto(&do_fadd);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotnumber);
|
||||
{
|
||||
// Check if {rhs} is a JSReceiver.
|
||||
Label if_rhsisreceiver(assembler, Label::kDeferred),
|
||||
if_rhsisnotreceiver(assembler, Label::kDeferred);
|
||||
assembler->Branch(
|
||||
assembler->Int32LessThanOrEqual(
|
||||
assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
|
||||
rhs_instance_type),
|
||||
&if_rhsisreceiver, &if_rhsisnotreceiver);
|
||||
|
||||
assembler->Bind(&if_rhsisreceiver);
|
||||
{
|
||||
// Convert {rhs} to a primitive first passing no hint.
|
||||
// TODO(bmeurer): Hook up ToPrimitiveStub here too.
|
||||
var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
|
||||
context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotreceiver);
|
||||
{
|
||||
// Convert {rhs} to a Number first.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotnumber);
|
||||
{
|
||||
// Check if {lhs} is a JSReceiver.
|
||||
Label if_lhsisreceiver(assembler, Label::kDeferred),
|
||||
if_lhsisnotreceiver(assembler);
|
||||
assembler->Branch(
|
||||
assembler->Int32LessThanOrEqual(
|
||||
assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
|
||||
lhs_instance_type),
|
||||
&if_lhsisreceiver, &if_lhsisnotreceiver);
|
||||
|
||||
assembler->Bind(&if_lhsisreceiver);
|
||||
{
|
||||
// Convert {lhs} to a primitive first passing no hint.
|
||||
// TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
|
||||
var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
|
||||
context, lhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotreceiver);
|
||||
{
|
||||
// Check if {rhs} is a JSReceiver.
|
||||
Label if_rhsisreceiver(assembler, Label::kDeferred),
|
||||
if_rhsisnotreceiver(assembler, Label::kDeferred);
|
||||
assembler->Branch(
|
||||
assembler->Int32LessThanOrEqual(
|
||||
assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
|
||||
rhs_instance_type),
|
||||
&if_rhsisreceiver, &if_rhsisnotreceiver);
|
||||
|
||||
assembler->Bind(&if_rhsisreceiver);
|
||||
{
|
||||
// Convert {rhs} to a primitive first passing no hint.
|
||||
// TODO(bmeurer): Hook up ToPrimitiveStub here too.
|
||||
var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
|
||||
context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotreceiver);
|
||||
{
|
||||
// Convert {lhs} to a Number first.
|
||||
Callable callable =
|
||||
CodeFactory::NonNumberToNumber(assembler->isolate());
|
||||
var_lhs.Bind(assembler->CallStub(callable, context, lhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&do_fadd);
|
||||
{
|
||||
Node* lhs_value = var_fadd_lhs.value();
|
||||
Node* rhs_value = var_fadd_rhs.value();
|
||||
Node* value = assembler->Float64Add(lhs_value, rhs_value);
|
||||
// TODO(bmeurer): Introduce a ChangeFloat64ToTagged.
|
||||
Node* result = assembler->Allocate(HeapNumber::kSize,
|
||||
compiler::CodeStubAssembler::kNone);
|
||||
assembler->StoreMapNoWriteBarrier(result,
|
||||
assembler->HeapNumberMapConstant());
|
||||
assembler->StoreHeapNumberValue(result, value);
|
||||
assembler->Return(result);
|
||||
}
|
||||
}
|
||||
|
||||
void SubtractStub::GenerateAssembly(
|
||||
compiler::CodeStubAssembler* assembler) const {
|
||||
typedef compiler::CodeStubAssembler::Label Label;
|
||||
typedef compiler::Node Node;
|
||||
typedef compiler::CodeStubAssembler::Variable Variable;
|
||||
|
||||
Node* context = assembler->Parameter(2);
|
||||
|
||||
// Shared entry for floating point subtraction.
|
||||
Label do_fsub(assembler);
|
||||
Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64),
|
||||
var_fsub_rhs(assembler, MachineRepresentation::kFloat64);
|
||||
|
||||
// We might need to loop several times due to ToPrimitive and/or ToNumber
|
||||
// conversions.
|
||||
Variable var_lhs(assembler, MachineRepresentation::kTagged),
|
||||
var_rhs(assembler, MachineRepresentation::kTagged);
|
||||
Variable* loop_vars[2] = {&var_lhs, &var_rhs};
|
||||
Label loop(assembler, 2, loop_vars);
|
||||
var_lhs.Bind(assembler->Parameter(0));
|
||||
var_rhs.Bind(assembler->Parameter(1));
|
||||
assembler->Goto(&loop);
|
||||
assembler->Bind(&loop);
|
||||
{
|
||||
// Load the current {lhs} and {rhs} values.
|
||||
Node* lhs = var_lhs.value();
|
||||
Node* rhs = var_rhs.value();
|
||||
|
||||
// Check if the {lhs} is a Smi or a HeapObject.
|
||||
Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_lhsissmi);
|
||||
{
|
||||
// Check if the {rhs} is also a Smi.
|
||||
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
|
||||
&if_rhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_rhsissmi);
|
||||
{
|
||||
// Try a fast Smi subtraction first.
|
||||
Node* pair = assembler->SmiSubWithOverflow(lhs, rhs);
|
||||
Node* result = assembler->Projection(0, pair);
|
||||
Node* overflow = assembler->Projection(1, pair);
|
||||
|
||||
// Check if the Smi subtraction overflowed.
|
||||
Label if_overflow(assembler), if_notoverflow(assembler);
|
||||
assembler->Branch(overflow, &if_overflow, &if_notoverflow);
|
||||
|
||||
assembler->Bind(&if_overflow);
|
||||
{
|
||||
// The result doesn't fit into Smi range.
|
||||
var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
|
||||
var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
|
||||
assembler->Goto(&do_fsub);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_notoverflow);
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotsmi);
|
||||
{
|
||||
// Load the map of the {rhs}.
|
||||
Node* rhs_map = assembler->LoadMap(rhs);
|
||||
|
||||
// Check if {rhs} is a HeapNumber.
|
||||
Label if_rhsisnumber(assembler),
|
||||
if_rhsisnotnumber(assembler, Label::kDeferred);
|
||||
Node* number_map = assembler->HeapNumberMapConstant();
|
||||
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
|
||||
&if_rhsisnumber, &if_rhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_rhsisnumber);
|
||||
{
|
||||
// Perform a floating point subtraction.
|
||||
var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
|
||||
var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
|
||||
assembler->Goto(&do_fsub);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotnumber);
|
||||
{
|
||||
// Convert the {rhs} to a Number first.
|
||||
Callable callable = CodeFactory::NonNumberToNumber(isolate());
|
||||
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotsmi);
|
||||
{
|
||||
// Load the map of the {lhs}.
|
||||
Node* lhs_map = assembler->LoadMap(lhs);
|
||||
|
||||
// Check if the {lhs} is a HeapNumber.
|
||||
Label if_lhsisnumber(assembler),
|
||||
if_lhsisnotnumber(assembler, Label::kDeferred);
|
||||
Node* number_map = assembler->HeapNumberMapConstant();
|
||||
assembler->Branch(assembler->WordEqual(lhs_map, number_map),
|
||||
&if_lhsisnumber, &if_lhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_lhsisnumber);
|
||||
{
|
||||
// Check if the {rhs} is a Smi.
|
||||
Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
|
||||
assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
|
||||
&if_rhsisnotsmi);
|
||||
|
||||
assembler->Bind(&if_rhsissmi);
|
||||
{
|
||||
// Perform a floating point subtraction.
|
||||
var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
|
||||
var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
|
||||
assembler->Goto(&do_fsub);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotsmi);
|
||||
{
|
||||
// Load the map of the {rhs}.
|
||||
Node* rhs_map = assembler->LoadMap(rhs);
|
||||
|
||||
// Check if the {rhs} is a HeapNumber.
|
||||
Label if_rhsisnumber(assembler),
|
||||
if_rhsisnotnumber(assembler, Label::kDeferred);
|
||||
assembler->Branch(assembler->WordEqual(rhs_map, number_map),
|
||||
&if_rhsisnumber, &if_rhsisnotnumber);
|
||||
|
||||
assembler->Bind(&if_rhsisnumber);
|
||||
{
|
||||
// Perform a floating point subtraction.
|
||||
var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
|
||||
var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
|
||||
assembler->Goto(&do_fsub);
|
||||
}
|
||||
|
||||
assembler->Bind(&if_rhsisnotnumber);
|
||||
{
|
||||
// Convert the {rhs} to a Number first.
|
||||
Callable callable = CodeFactory::NonNumberToNumber(isolate());
|
||||
var_rhs.Bind(assembler->CallStub(callable, context, rhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&if_lhsisnotnumber);
|
||||
{
|
||||
// Convert the {lhs} to a Number first.
|
||||
Callable callable = CodeFactory::NonNumberToNumber(isolate());
|
||||
var_lhs.Bind(assembler->CallStub(callable, context, lhs));
|
||||
assembler->Goto(&loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assembler->Bind(&do_fsub);
|
||||
{
|
||||
Node* lhs_value = var_fsub_lhs.value();
|
||||
Node* rhs_value = var_fsub_rhs.value();
|
||||
Node* value = assembler->Float64Sub(lhs_value, rhs_value);
|
||||
// TODO(bmeurer): Introduce a ChangeFloat64ToTagged.
|
||||
Node* result = assembler->Allocate(HeapNumber::kSize,
|
||||
compiler::CodeStubAssembler::kNone);
|
||||
assembler->StoreMapNoWriteBarrier(result,
|
||||
assembler->HeapNumberMapConstant());
|
||||
assembler->StoreHeapNumberValue(result, value);
|
||||
assembler->Return(result);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
enum RelationalComparisonMode {
|
||||
|
@ -111,6 +111,8 @@ namespace internal {
|
||||
V(AllocateUint8x16) \
|
||||
V(AllocateBool8x16) \
|
||||
V(StringLength) \
|
||||
V(Add) \
|
||||
V(Subtract) \
|
||||
V(LessThan) \
|
||||
V(LessThanOrEqual) \
|
||||
V(GreaterThan) \
|
||||
@ -667,6 +669,22 @@ class StringLengthStub : public TurboFanCodeStub {
|
||||
DEFINE_TURBOFAN_CODE_STUB(StringLength, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class AddStub final : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit AddStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp);
|
||||
DEFINE_TURBOFAN_CODE_STUB(Add, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class SubtractStub final : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit SubtractStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
||||
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp);
|
||||
DEFINE_TURBOFAN_CODE_STUB(Subtract, TurboFanCodeStub);
|
||||
};
|
||||
|
||||
class LessThanStub final : public TurboFanCodeStub {
|
||||
public:
|
||||
explicit LessThanStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
|
||||
|
@ -175,6 +175,16 @@ Node* CodeStubAssembler::SmiToFloat64(Node* value) {
|
||||
|
||||
Node* CodeStubAssembler::SmiAdd(Node* a, Node* b) { return IntPtrAdd(a, b); }
|
||||
|
||||
Node* CodeStubAssembler::SmiAddWithOverflow(Node* a, Node* b) {
|
||||
return IntPtrAddWithOverflow(a, b);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::SmiSub(Node* a, Node* b) { return IntPtrSub(a, b); }
|
||||
|
||||
Node* CodeStubAssembler::SmiSubWithOverflow(Node* a, Node* b) {
|
||||
return IntPtrSubWithOverflow(a, b);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); }
|
||||
|
||||
Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) {
|
||||
|
@ -63,8 +63,12 @@ class Schedule;
|
||||
|
||||
#define CODE_STUB_ASSEMBLER_BINARY_OP_LIST(V) \
|
||||
CODE_STUB_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \
|
||||
V(Float64Add) \
|
||||
V(Float64Sub) \
|
||||
V(IntPtrAdd) \
|
||||
V(IntPtrAddWithOverflow) \
|
||||
V(IntPtrSub) \
|
||||
V(IntPtrSubWithOverflow) \
|
||||
V(Int32Add) \
|
||||
V(Int32Sub) \
|
||||
V(Int32Mul) \
|
||||
@ -263,6 +267,9 @@ class CodeStubAssembler {
|
||||
|
||||
// Smi operations.
|
||||
Node* SmiAdd(Node* a, Node* b);
|
||||
Node* SmiAddWithOverflow(Node* a, Node* b);
|
||||
Node* SmiSub(Node* a, Node* b);
|
||||
Node* SmiSubWithOverflow(Node* a, Node* b);
|
||||
Node* SmiEqual(Node* a, Node* b);
|
||||
Node* SmiLessThan(Node* a, Node* b);
|
||||
Node* SmiLessThanOrEqual(Node* a, Node* b);
|
||||
|
@ -76,8 +76,6 @@ REPLACE_BINARY_OP_IC_CALL(JSBitwiseAnd, Token::BIT_AND)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSShiftLeft, Token::SHL)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSShiftRight, Token::SAR)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSShiftRightLogical, Token::SHR)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSAdd, Token::ADD)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSSubtract, Token::SUB)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSMultiply, Token::MUL)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSDivide, Token::DIV)
|
||||
REPLACE_BINARY_OP_IC_CALL(JSModulus, Token::MOD)
|
||||
@ -98,6 +96,8 @@ REPLACE_RUNTIME_CALL(JSConvertReceiver, Runtime::kConvertReceiver)
|
||||
Callable callable = CodeFactory::Name(isolate()); \
|
||||
ReplaceWithStubCall(node, callable, flags); \
|
||||
}
|
||||
REPLACE_STUB_CALL(Add)
|
||||
REPLACE_STUB_CALL(Subtract)
|
||||
REPLACE_STUB_CALL(LessThan)
|
||||
REPLACE_STUB_CALL(LessThanOrEqual)
|
||||
REPLACE_STUB_CALL(GreaterThan)
|
||||
|
@ -347,7 +347,9 @@ class RawMachineAssembler {
|
||||
}
|
||||
|
||||
INTPTR_BINOP(Int, Add);
|
||||
INTPTR_BINOP(Int, AddWithOverflow);
|
||||
INTPTR_BINOP(Int, Sub);
|
||||
INTPTR_BINOP(Int, SubWithOverflow);
|
||||
INTPTR_BINOP(Int, LessThan);
|
||||
INTPTR_BINOP(Int, LessThanOrEqual);
|
||||
INTPTR_BINOP(Word, Equal);
|
||||
|
@ -650,7 +650,7 @@ void Interpreter::DoBinaryOp(Runtime::FunctionId function_id,
|
||||
//
|
||||
// Add register <src> to accumulator.
|
||||
void Interpreter::DoAdd(InterpreterAssembler* assembler) {
|
||||
DoBinaryOp(Runtime::kAdd, assembler);
|
||||
DoBinaryOp(CodeFactory::Add(isolate_), assembler);
|
||||
}
|
||||
|
||||
|
||||
@ -658,7 +658,7 @@ void Interpreter::DoAdd(InterpreterAssembler* assembler) {
|
||||
//
|
||||
// Subtract register <src> from accumulator.
|
||||
void Interpreter::DoSub(InterpreterAssembler* assembler) {
|
||||
DoBinaryOp(Runtime::kSubtract, assembler);
|
||||
DoBinaryOp(CodeFactory::Subtract(isolate_), assembler);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user