[turbofan] Fix lazy deopt for JSToNumber conversions in binary operations.
This slightly hacky change provides lazy deopt points for to-number conversions in binops: When we deopt from a to-number conversion, we create a frame state with the already-converted value(s) so that we do not repeat the side effect of the conversion. Embenchen numbers are below. It is not quite clear what happened to fasta - the hot code looks nearly identical. Current: EmbenchenBox2d(RunTime): 12746 ms. d8-master: EmbenchenBox2d(RunTime): 13861 ms. ----------- bullet.js Current: EmbenchenBullet(RunTime): 17680 ms. d8-master: EmbenchenBullet(RunTime): 19170 ms. ----------- copy.js Current: EmbenchenCopy(RunTime): 4939 ms. d8-master: EmbenchenCopy(RunTime): 4943 ms. ----------- corrections.js Current: EmbenchenCorrections(RunTime): 6639 ms. d8-master: EmbenchenCorrections(RunTime): 6728 ms. ----------- fannkuch.js Current: EmbenchenFannkuch(RunTime): 4630 ms. d8-master: EmbenchenFannkuch(RunTime): 4872 ms. ----------- fasta.js Current: EmbenchenFasta(RunTime): 10209 ms. d8-master: EmbenchenFasta(RunTime): 9673 ms. ----------- lua_binarytrees.js Current: EmbenchenLuaBinaryTrees(RunTime): 12936 ms. d8-master: EmbenchenLuaBinaryTrees(RunTime): 15529 ms. ----------- memops.js Current: EmbenchenMemOps(RunTime): 7357 ms. d8-master: EmbenchenMemOps(RunTime): 7340 ms. ----------- primes.js Current: EmbenchenPrimes(RunTime): 7530 ms. d8-master: EmbenchenPrimes(RunTime): 7457 ms. ----------- skinning.js Current: EmbenchenSkinning(RunTime): 15832 ms. d8-master: EmbenchenSkinning(RunTime): 15630 ms. ----------- zlib.js Current: EmbenchenZLib(RunTime): 11176 ms. d8-master: EmbenchenZLib(RunTime): 11324 ms. BUG= Review URL: https://codereview.chromium.org/985713003 Cr-Commit-Position: refs/heads/master@{#27071}
This commit is contained in:
parent
dcb502a4ee
commit
6f559b7ec3
@ -204,7 +204,7 @@ Node* JSGraph::EmptyFrameState() {
|
||||
if (!empty_frame_state_.is_set()) {
|
||||
Node* values = graph()->NewNode(common()->StateValues(0));
|
||||
Node* state_node = graph()->NewNode(
|
||||
common()->FrameState(JS_FRAME, BailoutId(0),
|
||||
common()->FrameState(JS_FRAME, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore()),
|
||||
values, values, values, NoContextConstant(), UndefinedConstant());
|
||||
empty_frame_state_.set(state_node);
|
||||
|
@ -62,14 +62,36 @@ Reduction JSTypedLowering::ReplaceEagerly(Node* old, Node* node) {
|
||||
class JSBinopReduction FINAL {
|
||||
public:
|
||||
JSBinopReduction(JSTypedLowering* lowering, Node* node)
|
||||
: lowering_(lowering),
|
||||
node_(node),
|
||||
left_type_(NodeProperties::GetBounds(node->InputAt(0)).upper),
|
||||
right_type_(NodeProperties::GetBounds(node->InputAt(1)).upper) {}
|
||||
: lowering_(lowering), node_(node) {}
|
||||
|
||||
void ConvertInputsToNumber() {
|
||||
node_->ReplaceInput(0, ConvertToNumber(left()));
|
||||
node_->ReplaceInput(1, ConvertToNumber(right()));
|
||||
void ConvertPrimitiveInputsToNumber() {
|
||||
node_->ReplaceInput(0, ConvertPrimitiveToNumber(left()));
|
||||
node_->ReplaceInput(1, ConvertPrimitiveToNumber(right()));
|
||||
}
|
||||
|
||||
void ConvertInputsToNumber(Node* frame_state) {
|
||||
// To convert the inputs to numbers, we have to provide frame states
|
||||
// for lazy bailouts in the ToNumber conversions.
|
||||
// We use a little hack here: we take the frame state before the binary
|
||||
// operation and use it to construct the frame states for the conversion
|
||||
// so that after the deoptimization, the binary operation IC gets
|
||||
// already converted values from full code. This way we are sure that we
|
||||
// will not re-do any of the side effects.
|
||||
|
||||
Node* left_input =
|
||||
left_type()->Is(Type::PlainPrimitive())
|
||||
? ConvertPrimitiveToNumber(left())
|
||||
: ConvertToNumber(left(),
|
||||
CreateFrameStateForLeftInput(frame_state));
|
||||
|
||||
Node* right_input =
|
||||
right_type()->Is(Type::PlainPrimitive())
|
||||
? ConvertPrimitiveToNumber(right())
|
||||
: ConvertToNumber(right(), CreateFrameStateForRightInput(
|
||||
frame_state, left_input));
|
||||
|
||||
node_->ReplaceInput(0, left_input);
|
||||
node_->ReplaceInput(1, right_input);
|
||||
}
|
||||
|
||||
void ConvertInputsToUI32(Signedness left_signedness,
|
||||
@ -85,8 +107,9 @@ class JSBinopReduction FINAL {
|
||||
|
||||
// Convert inputs for bitwise shift operation (ES5 spec 11.7).
|
||||
void ConvertInputsForShift(Signedness left_signedness) {
|
||||
node_->ReplaceInput(0, ConvertToUI32(left(), left_signedness));
|
||||
Node* rnum = ConvertToUI32(right(), kUnsigned);
|
||||
node_->ReplaceInput(
|
||||
0, ConvertToUI32(ConvertPrimitiveToNumber(left()), left_signedness));
|
||||
Node* rnum = ConvertToUI32(ConvertPrimitiveToNumber(right()), kUnsigned);
|
||||
Type* rnum_type = NodeProperties::GetBounds(rnum).upper;
|
||||
if (!rnum_type->Is(lowering_->zero_thirtyone_range_)) {
|
||||
rnum = graph()->NewNode(machine()->Word32And(), rnum,
|
||||
@ -100,7 +123,6 @@ class JSBinopReduction FINAL {
|
||||
Node* r = right();
|
||||
node_->ReplaceInput(0, r);
|
||||
node_->ReplaceInput(1, l);
|
||||
std::swap(left_type_, right_type_);
|
||||
}
|
||||
|
||||
// Remove all effect and control inputs and outputs to this node and change
|
||||
@ -141,18 +163,18 @@ class JSBinopReduction FINAL {
|
||||
return ChangeToPureOperator(op, false, type);
|
||||
}
|
||||
|
||||
bool OneInputIs(Type* t) { return left_type_->Is(t) || right_type_->Is(t); }
|
||||
bool OneInputIs(Type* t) { return left_type()->Is(t) || right_type()->Is(t); }
|
||||
|
||||
bool BothInputsAre(Type* t) {
|
||||
return left_type_->Is(t) && right_type_->Is(t);
|
||||
return left_type()->Is(t) && right_type()->Is(t);
|
||||
}
|
||||
|
||||
bool OneInputCannotBe(Type* t) {
|
||||
return !left_type_->Maybe(t) || !right_type_->Maybe(t);
|
||||
return !left_type()->Maybe(t) || !right_type()->Maybe(t);
|
||||
}
|
||||
|
||||
bool NeitherInputCanBe(Type* t) {
|
||||
return !left_type_->Maybe(t) && !right_type_->Maybe(t);
|
||||
return !left_type()->Maybe(t) && !right_type()->Maybe(t);
|
||||
}
|
||||
|
||||
Node* effect() { return NodeProperties::GetEffectInput(node_); }
|
||||
@ -160,8 +182,12 @@ class JSBinopReduction FINAL {
|
||||
Node* context() { return NodeProperties::GetContextInput(node_); }
|
||||
Node* left() { return NodeProperties::GetValueInput(node_, 0); }
|
||||
Node* right() { return NodeProperties::GetValueInput(node_, 1); }
|
||||
Type* left_type() { return left_type_; }
|
||||
Type* right_type() { return right_type_; }
|
||||
Type* left_type() {
|
||||
return NodeProperties::GetBounds(node_->InputAt(0)).upper;
|
||||
}
|
||||
Type* right_type() {
|
||||
return NodeProperties::GetBounds(node_->InputAt(1)).upper;
|
||||
}
|
||||
|
||||
SimplifiedOperatorBuilder* simplified() { return lowering_->simplified(); }
|
||||
Graph* graph() const { return lowering_->graph(); }
|
||||
@ -173,8 +199,6 @@ class JSBinopReduction FINAL {
|
||||
private:
|
||||
JSTypedLowering* lowering_; // The containing lowering instance.
|
||||
Node* node_; // The original node.
|
||||
Type* left_type_; // Cache of the left input's type.
|
||||
Type* right_type_; // Cache of the right input's type.
|
||||
|
||||
Node* ConvertToString(Node* node) {
|
||||
// Avoid introducing too many eager ToString() operations.
|
||||
@ -186,27 +210,93 @@ class JSBinopReduction FINAL {
|
||||
return n;
|
||||
}
|
||||
|
||||
Node* ConvertToNumber(Node* node) {
|
||||
if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) {
|
||||
return lowering_->ConvertToNumber(node);
|
||||
Node* CreateFrameStateForLeftInput(Node* frame_state) {
|
||||
if (!FLAG_turbo_deoptimization) return nullptr;
|
||||
|
||||
FrameStateCallInfo state_info =
|
||||
OpParameter<FrameStateCallInfo>(frame_state);
|
||||
// If the frame state is already the right one, just return it.
|
||||
if (state_info.state_combine().kind() == OutputFrameStateCombine::kPokeAt &&
|
||||
state_info.state_combine().GetOffsetToPokeAt() == 1) {
|
||||
return frame_state;
|
||||
}
|
||||
|
||||
// Here, we smash the result of the conversion into the slot just below
|
||||
// the stack top. This is the slot that full code uses to store the
|
||||
// left operand.
|
||||
const Operator* op = jsgraph()->common()->FrameState(
|
||||
state_info.type(), state_info.bailout_id(),
|
||||
OutputFrameStateCombine::PokeAt(1));
|
||||
|
||||
return graph()->NewNode(op, frame_state->InputAt(0),
|
||||
frame_state->InputAt(1), frame_state->InputAt(2),
|
||||
frame_state->InputAt(3), frame_state->InputAt(4));
|
||||
}
|
||||
|
||||
Node* CreateFrameStateForRightInput(Node* frame_state, Node* converted_left) {
|
||||
if (!FLAG_turbo_deoptimization) return nullptr;
|
||||
|
||||
FrameStateCallInfo state_info =
|
||||
OpParameter<FrameStateCallInfo>(frame_state);
|
||||
|
||||
if (state_info.bailout_id() == BailoutId::None()) {
|
||||
// Dummy frame state => just leave it as is.
|
||||
return frame_state;
|
||||
}
|
||||
|
||||
// Create a frame state that stores the result of the operation to the
|
||||
// top of the stack (i.e., the slot used for the right operand).
|
||||
const Operator* op = jsgraph()->common()->FrameState(
|
||||
state_info.type(), state_info.bailout_id(),
|
||||
OutputFrameStateCombine::PokeAt(0));
|
||||
|
||||
// Change the left operand {converted_left} on the expression stack.
|
||||
Node* stack = frame_state->InputAt(2);
|
||||
DCHECK_EQ(stack->opcode(), IrOpcode::kStateValues);
|
||||
DCHECK_GE(stack->InputCount(), 2);
|
||||
|
||||
// TODO(jarin) Allocate in a local zone or a reusable buffer.
|
||||
NodeVector new_values(stack->InputCount(), zone());
|
||||
for (int i = 0; i < stack->InputCount(); i++) {
|
||||
if (i == stack->InputCount() - 2) {
|
||||
new_values[i] = converted_left;
|
||||
} else {
|
||||
new_values[i] = stack->InputAt(i);
|
||||
}
|
||||
}
|
||||
Node* new_stack =
|
||||
graph()->NewNode(stack->op(), stack->InputCount(), &new_values.front());
|
||||
|
||||
return graph()->NewNode(op, frame_state->InputAt(0),
|
||||
frame_state->InputAt(1), new_stack,
|
||||
frame_state->InputAt(3), frame_state->InputAt(4));
|
||||
}
|
||||
|
||||
Node* ConvertPrimitiveToNumber(Node* node) {
|
||||
return lowering_->ConvertPrimitiveToNumber(node);
|
||||
}
|
||||
|
||||
Node* ConvertToNumber(Node* node, Node* frame_state) {
|
||||
if (NodeProperties::GetBounds(node).upper->Is(Type::PlainPrimitive())) {
|
||||
return ConvertPrimitiveToNumber(node);
|
||||
} else if (!FLAG_turbo_deoptimization) {
|
||||
// We cannot use ConvertToPrimitiveNumber here because we need context
|
||||
// for converting general values.
|
||||
Node* const n = graph()->NewNode(javascript()->ToNumber(), node,
|
||||
context(), effect(), control());
|
||||
update_effect(n);
|
||||
return n;
|
||||
} else {
|
||||
Node* const n =
|
||||
graph()->NewNode(javascript()->ToNumber(), node, context(),
|
||||
frame_state, effect(), control());
|
||||
update_effect(n);
|
||||
return n;
|
||||
}
|
||||
// TODO(jarin) This ToNumber conversion can deoptimize, but we do not really
|
||||
// have a frame state to deoptimize to. Either we provide such a frame state
|
||||
// or we exclude the values that could lead to deoptimization (e.g., by
|
||||
// triggering eager deopt if the value is not plain).
|
||||
Node* const n = FLAG_turbo_deoptimization
|
||||
? graph()->NewNode(
|
||||
javascript()->ToNumber(), node, context(),
|
||||
jsgraph()->EmptyFrameState(), effect(), control())
|
||||
: graph()->NewNode(javascript()->ToNumber(), node,
|
||||
context(), effect(), control());
|
||||
update_effect(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
Node* ConvertToUI32(Node* node, Signedness signedness) {
|
||||
// Avoid introducing too many eager NumberToXXnt32() operations.
|
||||
node = ConvertToNumber(node);
|
||||
Type* type = NodeProperties::GetBounds(node).upper;
|
||||
if (signedness == kSigned) {
|
||||
if (!type->Is(Type::Signed32())) {
|
||||
@ -233,21 +323,14 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
|
||||
// JSAdd(x:number, y:number) => NumberAdd(x, y)
|
||||
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
|
||||
}
|
||||
if (r.BothInputsAre(Type::Primitive()) &&
|
||||
r.NeitherInputCanBe(Type::StringOrReceiver())) {
|
||||
if (r.NeitherInputCanBe(Type::StringOrReceiver())) {
|
||||
// JSAdd(x:-string, y:-string) => NumberAdd(ToNumber(x), ToNumber(y))
|
||||
r.ConvertInputsToNumber();
|
||||
Node* frame_state = FLAG_turbo_deoptimization
|
||||
? NodeProperties::GetFrameStateInput(node, 1)
|
||||
: nullptr;
|
||||
r.ConvertInputsToNumber(frame_state);
|
||||
return r.ChangeToPureOperator(simplified()->NumberAdd(), Type::Number());
|
||||
}
|
||||
#if 0
|
||||
// TODO(turbofan): General ToNumber disabled for now because:
|
||||
// a) The inserted ToNumber operation screws up observability of valueOf.
|
||||
// b) Deoptimization at ToNumber doesn't have corresponding bailout id.
|
||||
Type* maybe_string = Type::Union(Type::String(), Type::Receiver(), zone());
|
||||
if (r.NeitherInputCanBe(maybe_string)) {
|
||||
...
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
// TODO(turbofan): Lowering of StringAdd is disabled for now because:
|
||||
// a) The inserted ToString operation screws up valueOf vs. toString order.
|
||||
@ -265,79 +348,25 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSBitwiseOr(Node* node) {
|
||||
JSBinopReduction r(this, node);
|
||||
|
||||
// We can only reduce to Word32Or if we are sure the to-number conversions
|
||||
// cannot lazily deoptimize.
|
||||
bool shortcut_or_zero =
|
||||
!FLAG_turbo_deoptimization && r.OneInputIs(zero_range_);
|
||||
if (r.BothInputsAre(Type::Primitive()) || shortcut_or_zero) {
|
||||
// TODO(titzer): some Smi bitwise operations don't really require going
|
||||
// all the way to int32, which can save tagging/untagging for some
|
||||
// operations on some platforms.
|
||||
// TODO(turbofan): make this heuristic configurable for code size.
|
||||
r.ConvertInputsToUI32(kSigned, kSigned);
|
||||
return r.ChangeToPureOperator(machine()->Word32Or(), Type::Integral32());
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypedLowering::ReduceJSMultiply(Node* node) {
|
||||
JSBinopReduction r(this, node);
|
||||
|
||||
// We can only reduce to NumberMultiply if we are sure the to-number
|
||||
// conversions cannot lazily deoptimize.
|
||||
bool shortcut_multiply_one =
|
||||
!FLAG_turbo_deoptimization && r.OneInputIs(one_range_);
|
||||
|
||||
if (r.BothInputsAre(Type::Primitive()) || shortcut_multiply_one) {
|
||||
r.ConvertInputsToNumber();
|
||||
return r.ChangeToPureOperator(simplified()->NumberMultiply(),
|
||||
Type::Number());
|
||||
}
|
||||
// TODO(turbofan): relax/remove the effects of this operator in other cases.
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
|
||||
const Operator* numberOp) {
|
||||
JSBinopReduction r(this, node);
|
||||
if (r.BothInputsAre(Type::Primitive())) {
|
||||
r.ConvertInputsToNumber();
|
||||
return r.ChangeToPureOperator(numberOp, Type::Number());
|
||||
}
|
||||
#if 0
|
||||
// TODO(turbofan): General ToNumber disabled for now because:
|
||||
// a) The inserted ToNumber operation screws up observability of valueOf.
|
||||
// b) Deoptimization at ToNumber doesn't have corresponding bailout id.
|
||||
if (r.OneInputIs(Type::Primitive())) {
|
||||
// If at least one input is a primitive, then insert appropriate conversions
|
||||
// to number and reduce this operator to the given numeric one.
|
||||
// TODO(turbofan): make this heuristic configurable for code size.
|
||||
r.ConvertInputsToNumber();
|
||||
return r.ChangeToPureOperator(numberOp);
|
||||
}
|
||||
#endif
|
||||
// TODO(turbofan): relax/remove the effects of this operator in other cases.
|
||||
return NoChange();
|
||||
Node* frame_state = FLAG_turbo_deoptimization
|
||||
? NodeProperties::GetFrameStateInput(node, 1)
|
||||
: nullptr;
|
||||
r.ConvertInputsToNumber(frame_state);
|
||||
return r.ChangeToPureOperator(numberOp, Type::Number());
|
||||
}
|
||||
|
||||
|
||||
Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
|
||||
JSBinopReduction r(this, node);
|
||||
if (r.BothInputsAre(Type::Primitive())) {
|
||||
// TODO(titzer): some Smi bitwise operations don't really require going
|
||||
// all the way to int32, which can save tagging/untagging for some
|
||||
// operations
|
||||
// on some platforms.
|
||||
// TODO(turbofan): make this heuristic configurable for code size.
|
||||
r.ConvertInputsToUI32(kSigned, kSigned);
|
||||
return r.ChangeToPureOperator(intOp, Type::Integral32());
|
||||
}
|
||||
return NoChange();
|
||||
Node* frame_state = FLAG_turbo_deoptimization
|
||||
? NodeProperties::GetFrameStateInput(node, 1)
|
||||
: nullptr;
|
||||
r.ConvertInputsToNumber(frame_state);
|
||||
r.ConvertInputsToUI32(kSigned, kSigned);
|
||||
return r.ChangeToPureOperator(intOp, Type::Integral32());
|
||||
}
|
||||
|
||||
|
||||
@ -388,7 +417,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
|
||||
...
|
||||
}
|
||||
#endif
|
||||
if (r.BothInputsAre(Type::Primitive()) &&
|
||||
if (r.BothInputsAre(Type::PlainPrimitive()) &&
|
||||
r.OneInputCannotBe(Type::StringOrReceiver())) {
|
||||
const Operator* less_than;
|
||||
const Operator* less_than_or_equal;
|
||||
@ -400,7 +429,7 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
|
||||
less_than_or_equal = machine()->Int32LessThanOrEqual();
|
||||
} else {
|
||||
// TODO(turbofan): mixed signed/unsigned int32 comparisons.
|
||||
r.ConvertInputsToNumber();
|
||||
r.ConvertPrimitiveInputsToNumber();
|
||||
less_than = simplified()->NumberLessThan();
|
||||
less_than_or_equal = simplified()->NumberLessThanOrEqual();
|
||||
}
|
||||
@ -595,7 +624,7 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
|
||||
// to simply reuse the context of the {node}. However, ToNumber()
|
||||
// does not require a context anyways, so it's safe to discard it
|
||||
// here and pass the dummy context.
|
||||
Node* const value = ConvertToNumber(input->InputAt(i));
|
||||
Node* const value = ConvertPrimitiveToNumber(input->InputAt(i));
|
||||
if (i < node->InputCount()) {
|
||||
node->ReplaceInput(i, value);
|
||||
} else {
|
||||
@ -628,7 +657,7 @@ Reduction JSTypedLowering::ReduceJSToNumber(Node* node) {
|
||||
// to simply reuse the context of the {node}. However, ToNumber()
|
||||
// does not require a context anyways, so it's safe to discard it
|
||||
// here and pass the dummy context.
|
||||
Node* const value = ConvertToNumber(input->InputAt(i));
|
||||
Node* const value = ConvertPrimitiveToNumber(input->InputAt(i));
|
||||
node->ReplaceInput(i, value);
|
||||
}
|
||||
node->TrimInputCount(input_count);
|
||||
@ -911,7 +940,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
case IrOpcode::kJSGreaterThanOrEqual:
|
||||
return ReduceJSComparison(node);
|
||||
case IrOpcode::kJSBitwiseOr:
|
||||
return ReduceJSBitwiseOr(node);
|
||||
return ReduceInt32Binop(node, machine()->Word32Or());
|
||||
case IrOpcode::kJSBitwiseXor:
|
||||
return ReduceInt32Binop(node, machine()->Word32Xor());
|
||||
case IrOpcode::kJSBitwiseAnd:
|
||||
@ -927,7 +956,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
case IrOpcode::kJSSubtract:
|
||||
return ReduceNumberBinop(node, simplified()->NumberSubtract());
|
||||
case IrOpcode::kJSMultiply:
|
||||
return ReduceJSMultiply(node);
|
||||
return ReduceNumberBinop(node, simplified()->NumberMultiply());
|
||||
case IrOpcode::kJSDivide:
|
||||
return ReduceNumberBinop(node, simplified()->NumberDivide());
|
||||
case IrOpcode::kJSModulus:
|
||||
@ -955,7 +984,7 @@ Reduction JSTypedLowering::Reduce(Node* node) {
|
||||
}
|
||||
|
||||
|
||||
Node* JSTypedLowering::ConvertToNumber(Node* input) {
|
||||
Node* JSTypedLowering::ConvertPrimitiveToNumber(Node* input) {
|
||||
DCHECK(NodeProperties::GetBounds(input).upper->Is(Type::PlainPrimitive()));
|
||||
// Avoid inserting too many eager ToNumber() operations.
|
||||
Reduction const reduction = ReduceJSToNumberInput(input);
|
||||
|
@ -52,7 +52,7 @@ class JSTypedLowering FINAL : public Reducer {
|
||||
Reduction ReduceUI32Shift(Node* node, Signedness left_signedness,
|
||||
const Operator* shift_op);
|
||||
|
||||
Node* ConvertToNumber(Node* input);
|
||||
Node* ConvertPrimitiveToNumber(Node* input);
|
||||
template <IrOpcode::Value>
|
||||
Node* FindConversion(Node* input);
|
||||
void InsertConversion(Node* conversion);
|
||||
|
@ -95,6 +95,9 @@
|
||||
'test-debug/DebugStepFunctionApply': [PASS, NO_VARIANTS],
|
||||
'test-debug/DebugStepFunctionCall': [PASS, NO_VARIANTS],
|
||||
|
||||
# TODO(jarin): Cannot lazy-deoptimize from conversions before comparisons.
|
||||
'test-js-typed-lowering/OrderCompareEffects': [SKIP],
|
||||
|
||||
# TODO(jochen): Reenable after we removed the CHECK() from the marking queue.
|
||||
'test-mark-compact/MarkingDeque': [SKIP],
|
||||
|
||||
|
@ -67,7 +67,7 @@ class JSTypedLoweringTester : public HandleAndZoneScope {
|
||||
Node* stack = graph.NewNode(common.StateValues(0));
|
||||
|
||||
Node* state_node =
|
||||
graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0),
|
||||
graph.NewNode(common.FrameState(JS_FRAME, BailoutId::None(),
|
||||
OutputFrameStateCombine::Ignore()),
|
||||
parameters, locals, stack, context, UndefinedConstant());
|
||||
|
||||
|
40
test/mjsunit/compiler/deopt-tonumber-binop.js
Normal file
40
test/mjsunit/compiler/deopt-tonumber-binop.js
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2015 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
|
||||
//
|
||||
var f = (function() {
|
||||
"use asm";
|
||||
function f(x, y) {
|
||||
return x - y;
|
||||
}
|
||||
return f;
|
||||
})();
|
||||
|
||||
var counter = 0;
|
||||
|
||||
var deopt = { toString : function() {
|
||||
%DeoptimizeFunction(f);
|
||||
counter++;
|
||||
return "2";
|
||||
} };
|
||||
|
||||
var o = { toString : function() {
|
||||
counter++;
|
||||
return "1";
|
||||
} };
|
||||
|
||||
counter = 0;
|
||||
assertEquals(1, f(deopt, o));
|
||||
assertEquals(2, counter);
|
||||
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
counter = 0;
|
||||
assertEquals(-1, f(o, deopt));
|
||||
assertEquals(2, counter);
|
||||
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
counter = 0;
|
||||
assertEquals(0, f(deopt, deopt));
|
||||
assertEquals(2, counter);
|
@ -68,6 +68,7 @@
|
||||
'compare-known-objects-slow': [PASS, NO_VARIANTS],
|
||||
'elements-kind': [PASS, NO_VARIANTS],
|
||||
'opt-elements-kind': [PASS, NO_VARIANTS],
|
||||
'smi-representation': [PASS, NO_VARIANTS],
|
||||
|
||||
# Some tests are just too slow to run for now.
|
||||
'big-object-literal': [PASS, NO_VARIANTS],
|
||||
|
Loading…
Reference in New Issue
Block a user