Recognize special comparisons via pattern matching on the hydrogen graph.

Previously, comparisons against null/undefined and comparisons of the result of
typeof against a constant string were done syntactically. Now we do this via
pattern matching on the hydrogen graph, which opens up more opportunities for
better code generation, e.g. the following comparisons are now recognized to be
special:

   var bar = typeof foo;
   var baz = "undefined";
   if (bar == baz) ...

   var blah = undefined;
   if (hurz == blah) ...

If we did this handling of special cases even later at lithium generation time,
even more cases could be recognized, but this would involve bigger changes and
this CL handles most common cases.
Review URL: http://codereview.chromium.org/8242002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9612 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ba981dea
...@@ -5789,38 +5789,68 @@ Representation HGraphBuilder::ToRepresentation(TypeInfo info) { ...@@ -5789,38 +5789,68 @@ Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
Expression* sub_expr, HTypeof* typeof_expr,
Handle<String> check) { Handle<String> check) {
CHECK_ALIVE(VisitForTypeOf(sub_expr)); HValue* value = typeof_expr->value();
HValue* value = Pop();
HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check); HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check);
instr->set_position(expr->position()); instr->set_position(expr->position());
return ast_context()->ReturnControl(instr, expr->id()); ast_context()->ReturnControl(instr, expr->id());
typeof_expr->DeleteAndReplaceWith(NULL);
} }
bool HGraphBuilder::TryLiteralCompare(CompareOperation* expr) { static bool MatchLiteralCompareNil(HValue* left,
Expression *sub_expr; Token::Value op,
Handle<String> check; HValue* right,
if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { Handle<Object> nil,
HandleLiteralCompareTypeof(expr, sub_expr, check); HValue** expr) {
if (left->IsConstant() &&
HConstant::cast(left)->handle().is_identical_to(nil) &&
Token::IsEqualityOp(op)) {
*expr = right;
return true; return true;
} }
return false;
}
if (expr->IsLiteralCompareUndefined(&sub_expr)) {
HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
return true;
}
if (expr->IsLiteralCompareNull(&sub_expr)) { static bool MatchLiteralCompareTypeof(HValue* left,
HandleLiteralCompareNil(expr, sub_expr, kNullValue); Token::Value op,
HValue* right,
HTypeof** typeof_expr,
Handle<String>* check) {
if (left->IsTypeof() &&
Token::IsEqualityOp(op) &&
right->IsConstant() &&
HConstant::cast(right)->HasStringValue()) {
*typeof_expr = HTypeof::cast(left);
*check = Handle<String>::cast(HConstant::cast(right)->handle());
return true; return true;
} }
return false; return false;
} }
static bool IsLiteralCompareTypeof(HValue* left,
Token::Value op,
HValue* right,
HTypeof** typeof_expr,
Handle<String>* check) {
return MatchLiteralCompareTypeof(left, op, right, typeof_expr, check) ||
MatchLiteralCompareTypeof(right, op, left, typeof_expr, check);
}
static bool IsLiteralCompareNil(HValue* left,
Token::Value op,
HValue* right,
Handle<Object> nil,
HValue** expr) {
return MatchLiteralCompareNil(left, op, right, nil, expr) ||
MatchLiteralCompareNil(right, op, left, nil, expr);
}
void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
...@@ -5838,11 +5868,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -5838,11 +5868,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
return ast_context()->ReturnControl(instr, expr->id()); return ast_context()->ReturnControl(instr, expr->id());
} }
// Check for special cases that compare against literals.
if (TryLiteralCompare(expr)) return;
TypeInfo type_info = oracle()->CompareType(expr); TypeInfo type_info = oracle()->CompareType(expr);
// Check if this expression was ever executed according to type feedback. // Check if this expression was ever executed according to type feedback.
// Note that for the special typeof/null/undefined cases we get unknown here.
if (type_info.IsUninitialized()) { if (type_info.IsUninitialized()) {
AddInstruction(new(zone()) HSoftDeoptimize); AddInstruction(new(zone()) HSoftDeoptimize);
current_block()->MarkAsDeoptimizing(); current_block()->MarkAsDeoptimizing();
...@@ -5857,6 +5885,20 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -5857,6 +5885,20 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
HValue* left = Pop(); HValue* left = Pop();
Token::Value op = expr->op(); Token::Value op = expr->op();
HTypeof* typeof_expr = NULL;
Handle<String> check;
if (IsLiteralCompareTypeof(left, op, right, &typeof_expr, &check)) {
return HandleLiteralCompareTypeof(expr, typeof_expr, check);
}
HValue* sub_expr = NULL;
Factory* f = graph()->isolate()->factory();
if (IsLiteralCompareNil(left, op, right, f->undefined_value(), &sub_expr)) {
return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
}
if (IsLiteralCompareNil(left, op, right, f->null_value(), &sub_expr)) {
return HandleLiteralCompareNil(expr, sub_expr, kNullValue);
}
if (op == Token::INSTANCEOF) { if (op == Token::INSTANCEOF) {
// Check to see if the rhs of the instanceof is a global function not // Check to see if the rhs of the instanceof is a global function not
// residing in new space. If it is we assume that the function will stay the // residing in new space. If it is we assume that the function will stay the
...@@ -5945,13 +5987,11 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { ...@@ -5945,13 +5987,11 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
Expression* sub_expr, HValue* value,
NilValue nil) { NilValue nil) {
ASSERT(!HasStackOverflow()); ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL); ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor()); ASSERT(current_block()->HasPredecessor());
CHECK_ALIVE(VisitForValue(sub_expr));
HValue* value = Pop();
EqualityKind kind = EqualityKind kind =
expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality; expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality;
HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil); HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil);
......
...@@ -912,12 +912,11 @@ class HGraphBuilder: public AstVisitor { ...@@ -912,12 +912,11 @@ class HGraphBuilder: public AstVisitor {
HValue* receiver, HValue* receiver,
SmallMapList* types, SmallMapList* types,
Handle<String> name); Handle<String> name);
bool TryLiteralCompare(CompareOperation* expr);
void HandleLiteralCompareTypeof(CompareOperation* expr, void HandleLiteralCompareTypeof(CompareOperation* expr,
Expression* sub_expr, HTypeof* typeof_expr,
Handle<String> check); Handle<String> check);
void HandleLiteralCompareNil(CompareOperation* expr, void HandleLiteralCompareNil(CompareOperation* expr,
Expression* sub_expr, HValue* value,
NilValue nil); NilValue nil);
HStringCharCodeAt* BuildStringCharCodeAt(HValue* context, HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
......
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