[maglev] Add Box/UnboxNumbers and Float64Add nodes
- For simplicity we call a builtin when allocating a number. - Elision of boxing/unboxing nodes will be done in a followup CL. Bug: v8:7700 Change-Id: Iec4422d84c6597d3369ab512a1662adb0f077c98 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3602514 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Victor Gomes <victorgomes@chromium.org> Auto-Submit: Victor Gomes <victorgomes@chromium.org> Cr-Commit-Position: refs/heads/main@{#80178}
This commit is contained in:
parent
12284536d6
commit
755b7d863f
@ -240,6 +240,8 @@ namespace internal {
|
|||||||
TFC(AllocateInOldGeneration, Allocate) \
|
TFC(AllocateInOldGeneration, Allocate) \
|
||||||
TFC(AllocateRegularInOldGeneration, Allocate) \
|
TFC(AllocateRegularInOldGeneration, Allocate) \
|
||||||
\
|
\
|
||||||
|
TFC(NewHeapNumber, NewHeapNumber) \
|
||||||
|
\
|
||||||
/* TurboFan support builtins */ \
|
/* TurboFan support builtins */ \
|
||||||
TFS(CopyFastSmiOrObjectElements, kObject) \
|
TFS(CopyFastSmiOrObjectElements, kObject) \
|
||||||
TFC(GrowFastDoubleElements, GrowArrayElements) \
|
TFC(GrowFastDoubleElements, GrowArrayElements) \
|
||||||
|
@ -1080,6 +1080,11 @@ TF_BUILTIN(AdaptorWithBuiltinExitFrame, CodeStubAssembler) {
|
|||||||
new_target); // additional stack argument 4
|
new_target); // additional stack argument 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TF_BUILTIN(NewHeapNumber, CodeStubAssembler) {
|
||||||
|
auto val = UncheckedParameter<Float64T>(Descriptor::kValue);
|
||||||
|
Return(ChangeFloat64ToTagged(val));
|
||||||
|
}
|
||||||
|
|
||||||
TF_BUILTIN(AllocateInYoungGeneration, CodeStubAssembler) {
|
TF_BUILTIN(AllocateInYoungGeneration, CodeStubAssembler) {
|
||||||
auto requested_size = UncheckedParameter<IntPtrT>(Descriptor::kRequestedSize);
|
auto requested_size = UncheckedParameter<IntPtrT>(Descriptor::kRequestedSize);
|
||||||
CSA_CHECK(this, IsValidPositiveSmi(requested_size));
|
CSA_CHECK(this, IsValidPositiveSmi(requested_size));
|
||||||
|
@ -310,6 +310,13 @@ constexpr auto WasmFloat64ToNumberDescriptor::registers() {
|
|||||||
return RegisterArray(ecx);
|
return RegisterArray(ecx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
constexpr auto NewHeapNumberDescriptor::registers() {
|
||||||
|
// Work around using eax, whose register code is 0, and leads to the FP
|
||||||
|
// parameter being passed via xmm0, which is not allocatable on ia32.
|
||||||
|
return RegisterArray(ecx);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
|
||||||
|
@ -189,6 +189,14 @@ StaticCallInterfaceDescriptor<DerivedDescriptor>::GetRegisterParameter(int i) {
|
|||||||
return DerivedDescriptor::registers()[i];
|
return DerivedDescriptor::registers()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
template <typename DerivedDescriptor>
|
||||||
|
constexpr DoubleRegister
|
||||||
|
StaticCallInterfaceDescriptor<DerivedDescriptor>::GetDoubleRegisterParameter(
|
||||||
|
int i) {
|
||||||
|
return DoubleRegister::from_code(DerivedDescriptor::registers()[i].code());
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
constexpr Register FastNewObjectDescriptor::TargetRegister() {
|
constexpr Register FastNewObjectDescriptor::TargetRegister() {
|
||||||
return kJSFunctionRegister;
|
return kJSFunctionRegister;
|
||||||
|
@ -102,6 +102,7 @@ namespace internal {
|
|||||||
V(LoadWithReceiverBaseline) \
|
V(LoadWithReceiverBaseline) \
|
||||||
V(LoadWithVector) \
|
V(LoadWithVector) \
|
||||||
V(LookupBaseline) \
|
V(LookupBaseline) \
|
||||||
|
V(NewHeapNumber) \
|
||||||
V(NoContext) \
|
V(NoContext) \
|
||||||
V(ResumeGenerator) \
|
V(ResumeGenerator) \
|
||||||
V(ResumeGeneratorBaseline) \
|
V(ResumeGeneratorBaseline) \
|
||||||
@ -480,6 +481,10 @@ class StaticCallInterfaceDescriptor : public CallInterfaceDescriptor {
|
|||||||
static constexpr inline Register* GetRegisterData();
|
static constexpr inline Register* GetRegisterData();
|
||||||
static constexpr inline Register GetRegisterParameter(int i);
|
static constexpr inline Register GetRegisterParameter(int i);
|
||||||
|
|
||||||
|
// Interface descriptors don't really support double registers.
|
||||||
|
// This reinterprets the i-th register as a double with the same code.
|
||||||
|
static constexpr inline DoubleRegister GetDoubleRegisterParameter(int i);
|
||||||
|
|
||||||
explicit StaticCallInterfaceDescriptor(CallDescriptors::Key key)
|
explicit StaticCallInterfaceDescriptor(CallDescriptors::Key key)
|
||||||
: CallInterfaceDescriptor(key) {}
|
: CallInterfaceDescriptor(key) {}
|
||||||
|
|
||||||
@ -714,6 +719,20 @@ class AllocateDescriptor
|
|||||||
static constexpr auto registers();
|
static constexpr auto registers();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NewHeapNumberDescriptor
|
||||||
|
: public StaticCallInterfaceDescriptor<NewHeapNumberDescriptor> {
|
||||||
|
public:
|
||||||
|
DEFINE_PARAMETERS_NO_CONTEXT(kValue)
|
||||||
|
DEFINE_RESULT_AND_PARAMETER_TYPES(MachineType::TaggedPointer(), // Result
|
||||||
|
MachineType::Float64()) // kValue
|
||||||
|
DECLARE_DESCRIPTOR(NewHeapNumberDescriptor)
|
||||||
|
|
||||||
|
#if V8_TARGET_ARCH_IA32
|
||||||
|
// We need a custom descriptor on ia32 to avoid using xmm0.
|
||||||
|
static constexpr inline auto registers();
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
// This descriptor defines the JavaScript calling convention that can be used
|
// This descriptor defines the JavaScript calling convention that can be used
|
||||||
// by stubs: target, new.target, argc and context are passed in registers while
|
// by stubs: target, new.target, argc and context are passed in registers while
|
||||||
// receiver and the rest of the JS arguments are passed on the stack.
|
// receiver and the rest of the JS arguments are passed on the stack.
|
||||||
|
@ -142,10 +142,19 @@ inline Register ToRegister(const compiler::InstructionOperand& operand) {
|
|||||||
return compiler::AllocatedOperand::cast(operand).GetRegister();
|
return compiler::AllocatedOperand::cast(operand).GetRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline DoubleRegister ToDoubleRegister(
|
||||||
|
const compiler::InstructionOperand& operand) {
|
||||||
|
return compiler::AllocatedOperand::cast(operand).GetDoubleRegister();
|
||||||
|
}
|
||||||
|
|
||||||
inline Register ToRegister(const ValueLocation& location) {
|
inline Register ToRegister(const ValueLocation& location) {
|
||||||
return ToRegister(location.operand());
|
return ToRegister(location.operand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline DoubleRegister ToDoubleRegister(const ValueLocation& location) {
|
||||||
|
return ToDoubleRegister(location.operand());
|
||||||
|
}
|
||||||
|
|
||||||
inline void MaglevCodeGenState::DefineSafepointStackSlots(
|
inline void MaglevCodeGenState::DefineSafepointStackSlots(
|
||||||
SafepointTableBuilder::Safepoint& safepoint) const {
|
SafepointTableBuilder::Safepoint& safepoint) const {
|
||||||
for (int stack_slot = 0; stack_slot < tagged_slots_; stack_slot++) {
|
for (int stack_slot = 0; stack_slot < tagged_slots_; stack_slot++) {
|
||||||
|
@ -207,6 +207,22 @@ void MaglevGraphBuilder::VisitBinaryOperation() {
|
|||||||
SetAccumulator(AddNewNode<Int32AddWithOverflow>({left, right}));
|
SetAccumulator(AddNewNode<Int32AddWithOverflow>({left, right}));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (hint == BinaryOperationHint::kNumber) {
|
||||||
|
ValueNode *left, *right;
|
||||||
|
if (IsRegisterEqualToAccumulator(0)) {
|
||||||
|
left = right =
|
||||||
|
AddNewNode<CheckedFloat64Unbox>({LoadRegisterTagged(0)});
|
||||||
|
} else {
|
||||||
|
left = AddNewNode<CheckedFloat64Unbox>({LoadRegisterTagged(0)});
|
||||||
|
right = AddNewNode<CheckedFloat64Unbox>({GetAccumulatorTagged()});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kOperation == Operation::kAdd) {
|
||||||
|
ValueNode* result = AddNewNode<Float64Add>({left, right});
|
||||||
|
SetAccumulator(AddNewNode<Float64Box>({result}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,14 +88,18 @@ class MaglevGraphVerifier {
|
|||||||
case Opcode::kBranchIfTrue:
|
case Opcode::kBranchIfTrue:
|
||||||
case Opcode::kBranchIfToBooleanTrue:
|
case Opcode::kBranchIfToBooleanTrue:
|
||||||
case Opcode::kReturn:
|
case Opcode::kReturn:
|
||||||
// Generic tagged unary operations.
|
case Opcode::kCheckedFloat64Unbox:
|
||||||
DCHECK_EQ(node->input_count(), 1);
|
DCHECK_EQ(node->input_count(), 1);
|
||||||
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
|
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
|
||||||
break;
|
break;
|
||||||
case Opcode::kCheckedSmiTag:
|
case Opcode::kCheckedSmiTag:
|
||||||
// Untagged unary operations.
|
DCHECK_EQ(node->input_count(), 1);
|
||||||
CheckValueInputIs(node, 0, ValueRepresentation::kInt32);
|
CheckValueInputIs(node, 0, ValueRepresentation::kInt32);
|
||||||
break;
|
break;
|
||||||
|
case Opcode::kFloat64Box:
|
||||||
|
DCHECK_EQ(node->input_count(), 1);
|
||||||
|
CheckValueInputIs(node, 0, ValueRepresentation::kFloat64);
|
||||||
|
break;
|
||||||
case Opcode::kGenericAdd:
|
case Opcode::kGenericAdd:
|
||||||
case Opcode::kGenericSubtract:
|
case Opcode::kGenericSubtract:
|
||||||
case Opcode::kGenericMultiply:
|
case Opcode::kGenericMultiply:
|
||||||
@ -119,16 +123,20 @@ class MaglevGraphVerifier {
|
|||||||
// TODO(victorgomes): Can we check that first input is an Object?
|
// TODO(victorgomes): Can we check that first input is an Object?
|
||||||
case Opcode::kStoreField:
|
case Opcode::kStoreField:
|
||||||
case Opcode::kLoadNamedGeneric:
|
case Opcode::kLoadNamedGeneric:
|
||||||
// Generic tagged binary operations.
|
|
||||||
DCHECK_EQ(node->input_count(), 2);
|
DCHECK_EQ(node->input_count(), 2);
|
||||||
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
|
CheckValueInputIs(node, 0, ValueRepresentation::kTagged);
|
||||||
CheckValueInputIs(node, 1, ValueRepresentation::kTagged);
|
CheckValueInputIs(node, 1, ValueRepresentation::kTagged);
|
||||||
break;
|
break;
|
||||||
case Opcode::kInt32AddWithOverflow:
|
case Opcode::kInt32AddWithOverflow:
|
||||||
// Untagged binary operations.
|
DCHECK_EQ(node->input_count(), 2);
|
||||||
CheckValueInputIs(node, 0, ValueRepresentation::kInt32);
|
CheckValueInputIs(node, 0, ValueRepresentation::kInt32);
|
||||||
CheckValueInputIs(node, 1, ValueRepresentation::kInt32);
|
CheckValueInputIs(node, 1, ValueRepresentation::kInt32);
|
||||||
break;
|
break;
|
||||||
|
case Opcode::kFloat64Add:
|
||||||
|
DCHECK_EQ(node->input_count(), 2);
|
||||||
|
CheckValueInputIs(node, 0, ValueRepresentation::kFloat64);
|
||||||
|
CheckValueInputIs(node, 1, ValueRepresentation::kFloat64);
|
||||||
|
break;
|
||||||
case Opcode::kCall:
|
case Opcode::kCall:
|
||||||
case Opcode::kPhi:
|
case Opcode::kPhi:
|
||||||
// All inputs should be tagged.
|
// All inputs should be tagged.
|
||||||
|
@ -85,6 +85,10 @@ void UseFixed(Input& input, Register reg) {
|
|||||||
input.SetUnallocated(compiler::UnallocatedOperand::FIXED_REGISTER, reg.code(),
|
input.SetUnallocated(compiler::UnallocatedOperand::FIXED_REGISTER, reg.code(),
|
||||||
GetVirtualRegister(input.node()));
|
GetVirtualRegister(input.node()));
|
||||||
}
|
}
|
||||||
|
void UseFixed(Input& input, DoubleRegister reg) {
|
||||||
|
input.SetUnallocated(compiler::UnallocatedOperand::FIXED_FP_REGISTER,
|
||||||
|
reg.code(), GetVirtualRegister(input.node()));
|
||||||
|
}
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
// Code gen helpers.
|
// Code gen helpers.
|
||||||
@ -748,6 +752,58 @@ void Int32AddWithOverflow::GenerateCode(MaglevCodeGenState* code_gen_state,
|
|||||||
EmitEagerDeoptIf(overflow, code_gen_state, this);
|
EmitEagerDeoptIf(overflow, code_gen_state, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Float64Box::AllocateVreg(MaglevVregAllocationState* vreg_state,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
using D = NewHeapNumberDescriptor;
|
||||||
|
UseFixed(input(), D::GetDoubleRegisterParameter(D::kValue));
|
||||||
|
DefineAsFixed(vreg_state, this, kReturnRegister0);
|
||||||
|
}
|
||||||
|
void Float64Box::GenerateCode(MaglevCodeGenState* code_gen_state,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
// TODO(victorgomes): Inline heap number allocation.
|
||||||
|
__ CallBuiltin(Builtin::kNewHeapNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckedFloat64Unbox::AllocateVreg(MaglevVregAllocationState* vreg_state,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
UseRegister(input());
|
||||||
|
DefineAsRegister(vreg_state, this);
|
||||||
|
}
|
||||||
|
void CheckedFloat64Unbox::GenerateCode(MaglevCodeGenState* code_gen_state,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
Register value = ToRegister(input());
|
||||||
|
Label is_not_smi, done;
|
||||||
|
// Check if Smi.
|
||||||
|
__ testb(value, Immediate(1));
|
||||||
|
__ j(not_zero, &is_not_smi);
|
||||||
|
// If Smi, convert to Float64.
|
||||||
|
__ sarl(value, Immediate(1));
|
||||||
|
__ Cvtlsi2sd(ToDoubleRegister(result()), value);
|
||||||
|
__ jmp(&done);
|
||||||
|
__ bind(&is_not_smi);
|
||||||
|
// Check if HeapNumber, deopt otherwise.
|
||||||
|
__ CompareRoot(FieldOperand(value, HeapObject::kMapOffset),
|
||||||
|
RootIndex::kHeapNumberMap);
|
||||||
|
EmitEagerDeoptIf(not_equal, code_gen_state, this);
|
||||||
|
__ Movsd(ToDoubleRegister(result()),
|
||||||
|
FieldOperand(value, HeapNumber::kValueOffset));
|
||||||
|
__ bind(&done);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Float64Add::AllocateVreg(MaglevVregAllocationState* vreg_state,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
UseRegister(left_input());
|
||||||
|
UseRegister(right_input());
|
||||||
|
DefineSameAsFirst(vreg_state, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Float64Add::GenerateCode(MaglevCodeGenState* code_gen_state,
|
||||||
|
const ProcessingState& state) {
|
||||||
|
DoubleRegister left = ToDoubleRegister(left_input());
|
||||||
|
DoubleRegister right = ToDoubleRegister(right_input());
|
||||||
|
__ Addsd(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
void Phi::AllocateVreg(MaglevVregAllocationState* vreg_state,
|
void Phi::AllocateVreg(MaglevVregAllocationState* vreg_state,
|
||||||
const ProcessingState& state) {
|
const ProcessingState& state) {
|
||||||
// Phi inputs are processed in the post-process, once loop phis' inputs'
|
// Phi inputs are processed in the post-process, once loop phis' inputs'
|
||||||
|
@ -80,6 +80,9 @@ class CompactInterpreterFrameState;
|
|||||||
V(CheckedSmiUntag) \
|
V(CheckedSmiUntag) \
|
||||||
V(Int32AddWithOverflow) \
|
V(Int32AddWithOverflow) \
|
||||||
V(Int32Constant) \
|
V(Int32Constant) \
|
||||||
|
V(Float64Box) \
|
||||||
|
V(CheckedFloat64Unbox) \
|
||||||
|
V(Float64Add) \
|
||||||
GENERIC_OPERATIONS_NODE_LIST(V)
|
GENERIC_OPERATIONS_NODE_LIST(V)
|
||||||
|
|
||||||
#define NODE_LIST(V) \
|
#define NODE_LIST(V) \
|
||||||
@ -828,6 +831,12 @@ class ValueNode : public Node {
|
|||||||
|
|
||||||
compiler::AllocatedOperand allocation() const {
|
compiler::AllocatedOperand allocation() const {
|
||||||
if (has_register()) {
|
if (has_register()) {
|
||||||
|
if (use_double_register()) {
|
||||||
|
return compiler::AllocatedOperand(
|
||||||
|
compiler::LocationOperand::REGISTER,
|
||||||
|
MachineRepresentation::kFloat64,
|
||||||
|
double_registers_with_result_.first().code());
|
||||||
|
}
|
||||||
return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
|
return compiler::AllocatedOperand(compiler::LocationOperand::REGISTER,
|
||||||
GetMachineRepresentation(),
|
GetMachineRepresentation(),
|
||||||
FirstRegisterCode());
|
FirstRegisterCode());
|
||||||
@ -1106,6 +1115,56 @@ class Int32AddWithOverflow
|
|||||||
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
|
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Float64Box : public FixedInputValueNodeT<1, Float64Box> {
|
||||||
|
using Base = FixedInputValueNodeT<1, Float64Box>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Float64Box(uint32_t bitfield) : Base(bitfield) {}
|
||||||
|
|
||||||
|
static constexpr OpProperties kProperties = OpProperties::Call();
|
||||||
|
|
||||||
|
Input& input() { return Node::input(0); }
|
||||||
|
|
||||||
|
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
|
||||||
|
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
|
||||||
|
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CheckedFloat64Unbox
|
||||||
|
: public FixedInputValueNodeT<1, CheckedFloat64Unbox> {
|
||||||
|
using Base = FixedInputValueNodeT<1, CheckedFloat64Unbox>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CheckedFloat64Unbox(uint32_t bitfield) : Base(bitfield) {}
|
||||||
|
|
||||||
|
static constexpr OpProperties kProperties =
|
||||||
|
OpProperties::EagerDeopt() | OpProperties::Float64();
|
||||||
|
|
||||||
|
Input& input() { return Node::input(0); }
|
||||||
|
|
||||||
|
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
|
||||||
|
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
|
||||||
|
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Float64Add : public FixedInputValueNodeT<2, Float64Add> {
|
||||||
|
using Base = FixedInputValueNodeT<2, Float64Add>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Float64Add(uint32_t bitfield) : Base(bitfield) {}
|
||||||
|
|
||||||
|
static constexpr OpProperties kProperties = OpProperties::Float64();
|
||||||
|
|
||||||
|
static constexpr int kLeftIndex = 0;
|
||||||
|
static constexpr int kRightIndex = 1;
|
||||||
|
Input& left_input() { return Node::input(kLeftIndex); }
|
||||||
|
Input& right_input() { return Node::input(kRightIndex); }
|
||||||
|
|
||||||
|
void AllocateVreg(MaglevVregAllocationState*, const ProcessingState&);
|
||||||
|
void GenerateCode(MaglevCodeGenState*, const ProcessingState&);
|
||||||
|
void PrintParams(std::ostream&, MaglevGraphLabeller*) const {}
|
||||||
|
};
|
||||||
|
|
||||||
class InitialValue : public FixedInputValueNodeT<0, InitialValue> {
|
class InitialValue : public FixedInputValueNodeT<0, InitialValue> {
|
||||||
using Base = FixedInputValueNodeT<0, InitialValue>;
|
using Base = FixedInputValueNodeT<0, InitialValue>;
|
||||||
|
|
||||||
|
30
test/mjsunit/maglev/add-number.js
Normal file
30
test/mjsunit/maglev/add-number.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --allow-natives-syntax --maglev --no-stress-opt
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
function add(x, y) {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
%PrepareFunctionForOptimization(add);
|
||||||
|
assertEquals(4.2, add(2.1, 2.1));
|
||||||
|
|
||||||
|
%OptimizeMaglevOnNextCall(add);
|
||||||
|
assertEquals(4.2, add(2.1, 2.1));
|
||||||
|
assertTrue(isMaglevved(add));
|
||||||
|
|
||||||
|
// We don't deopt if we use smis.
|
||||||
|
assertEquals(42, add(22, 20));
|
||||||
|
assertTrue(isMaglevved(add));
|
||||||
|
|
||||||
|
// We deopt if not a number.
|
||||||
|
assertEquals("42", add("4", "2"));
|
||||||
|
assertFalse(isMaglevved(add));
|
||||||
|
|
||||||
|
// TODO(victorgomes): Fix deopt when we have a float,
|
||||||
|
// i.e., add(4, "2") will create a float with number 4
|
||||||
|
// and correctly deopt, but the state is bogus.
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user