Commit 69c84fe4 authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Fix deoptimization stack layout for fast literal comparisons.

BUG=chromium:592341
LOG=n

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

Cr-Commit-Position: refs/heads/master@{#34615}
parent d238b953
...@@ -2810,8 +2810,57 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { ...@@ -2810,8 +2810,57 @@ void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
} }
} }
void AstGraphBuilder::VisitLiteralCompareNil(CompareOperation* expr,
Expression* sub_expr,
Node* nil_value) {
const Operator* op = nullptr;
switch (expr->op()) {
case Token::EQ:
op = javascript()->Equal();
break;
case Token::EQ_STRICT:
op = javascript()->StrictEqual();
break;
default:
UNREACHABLE();
}
VisitForValue(sub_expr);
FrameStateBeforeAndAfter states(this, sub_expr->id());
Node* value_to_compare = environment()->Pop();
Node* value = NewNode(op, value_to_compare, nil_value);
states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
return ast_context()->ProduceValue(value);
}
void AstGraphBuilder::VisitLiteralCompareTypeof(CompareOperation* expr,
Expression* sub_expr,
Handle<String> check) {
VisitTypeofExpression(sub_expr);
FrameStateBeforeAndAfter states(this, sub_expr->id());
Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop());
Node* value = NewNode(javascript()->StrictEqual(), typeof_arg,
jsgraph()->Constant(check));
states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
return ast_context()->ProduceValue(value);
}
void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
// Check for a few fast cases. The AST visiting behavior must be in sync
// with the full codegen: We don't push both left and right values onto
// the expression stack when one side is a special-case literal.
Expression* sub_expr = nullptr;
Handle<String> check;
if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
return VisitLiteralCompareTypeof(expr, sub_expr, check);
}
if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) {
return VisitLiteralCompareNil(expr, sub_expr,
jsgraph()->UndefinedConstant());
}
if (expr->IsLiteralCompareNull(&sub_expr)) {
return VisitLiteralCompareNil(expr, sub_expr, jsgraph()->NullConstant());
}
const Operator* op; const Operator* op;
switch (expr->op()) { switch (expr->op()) {
case Token::EQ: case Token::EQ:
...@@ -2973,23 +3022,25 @@ void AstGraphBuilder::VisitVoid(UnaryOperation* expr) { ...@@ -2973,23 +3022,25 @@ void AstGraphBuilder::VisitVoid(UnaryOperation* expr) {
ast_context()->ProduceValue(value); ast_context()->ProduceValue(value);
} }
void AstGraphBuilder::VisitTypeofExpression(Expression* expr) {
void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) { if (expr->IsVariableProxy()) {
Node* operand;
if (expr->expression()->IsVariableProxy()) {
// Typeof does not throw a reference error on global variables, hence we // Typeof does not throw a reference error on global variables, hence we
// perform a non-contextual load in case the operand is a variable proxy. // perform a non-contextual load in case the operand is a variable proxy.
VariableProxy* proxy = expr->expression()->AsVariableProxy(); VariableProxy* proxy = expr->AsVariableProxy();
VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
FrameStateBeforeAndAfter states(this, BeforeId(proxy)); FrameStateBeforeAndAfter states(this, BeforeId(proxy));
operand = Node* load =
BuildVariableLoad(proxy->var(), expr->expression()->id(), states, pair, BuildVariableLoad(proxy->var(), expr->id(), states, pair,
OutputFrameStateCombine::Push(), INSIDE_TYPEOF); OutputFrameStateCombine::Push(), INSIDE_TYPEOF);
environment()->Push(load);
} else { } else {
VisitForValue(expr->expression()); VisitForValue(expr);
operand = environment()->Pop();
} }
Node* value = NewNode(javascript()->TypeOf(), operand); }
void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
VisitTypeofExpression(expr->expression());
Node* value = NewNode(javascript()->TypeOf(), environment()->Pop());
ast_context()->ProduceValue(value); ast_context()->ProduceValue(value);
} }
......
...@@ -419,11 +419,20 @@ class AstGraphBuilder : public AstVisitor { ...@@ -419,11 +419,20 @@ class AstGraphBuilder : public AstVisitor {
void VisitTypeof(UnaryOperation* expr); void VisitTypeof(UnaryOperation* expr);
void VisitNot(UnaryOperation* expr); void VisitNot(UnaryOperation* expr);
// Dispatched from VisitTypeof, VisitLiteralCompareTypeof.
void VisitTypeofExpression(Expression* expr);
// Dispatched from VisitBinaryOperation. // Dispatched from VisitBinaryOperation.
void VisitComma(BinaryOperation* expr); void VisitComma(BinaryOperation* expr);
void VisitLogicalExpression(BinaryOperation* expr); void VisitLogicalExpression(BinaryOperation* expr);
void VisitArithmeticExpression(BinaryOperation* expr); void VisitArithmeticExpression(BinaryOperation* expr);
// Dispatched from VisitCompareOperation.
void VisitLiteralCompareNil(CompareOperation* expr, Expression* sub_expr,
Node* nil_value);
void VisitLiteralCompareTypeof(CompareOperation* expr, Expression* sub_expr,
Handle<String> check);
// Dispatched from VisitForInStatement. // Dispatched from VisitForInStatement.
void VisitForInAssignment(Expression* expr, Node* value, void VisitForInAssignment(Expression* expr, Node* value,
const VectorSlotPair& feedback, const VectorSlotPair& feedback,
......
// Copyright 2016 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
function id(a) {
return a;
}
(function LiteralCompareNullDeopt() {
function f() {
return id(null == %DeoptimizeNow());
}
%OptimizeFunctionOnNextCall(f);
assertTrue(f());
})();
(function LiteralCompareUndefinedDeopt() {
function f() {
return id(undefined == %DeoptimizeNow());
}
%OptimizeFunctionOnNextCall(f);
assertTrue(f());
})();
(function LiteralCompareTypeofDeopt() {
function f() {
return id("undefined" == typeof(%DeoptimizeNow()));
}
%OptimizeFunctionOnNextCall(f);
assertTrue(f());
})();
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