Recognize special comparisons via pattern matching on the hydrogen graph, 2nd attempt.

This time, we initially leave the HTypeof instruction in the Hydrogen graph,
even for the special cases. We later try to remove this instruction (and any
HConstant) in the canonicalization pass, if possible. Always removing the
HTypeof during the initial graph construction is wrong if e.g. it is used in an
HSimulate.

The removals can be generalized a bit, but this will happen in a separate CL.

TEST=mjsunit/optimized-typeof.js
Review URL: http://codereview.chromium.org/8334021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9688 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e8a26d1e
......@@ -787,6 +787,16 @@ void HTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
}
HValue* HConstant::Canonicalize() {
return HasNoUses() && !IsBlockEntry() ? NULL : this;
}
HValue* HTypeof::Canonicalize() {
return HasNoUses() && !IsBlockEntry() ? NULL : this;
}
void HTypeof::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
}
......
......@@ -2287,6 +2287,7 @@ class HConstant: public HTemplateInstruction<0> {
}
virtual bool EmitAtUses() { return !representation().IsDouble(); }
virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual HType CalculateInferredType();
bool IsInteger() const { return handle_->IsSmi(); }
......@@ -4159,6 +4160,7 @@ class HTypeof: public HTemplateInstruction<2> {
HValue* context() { return OperandAt(0); }
HValue* value() { return OperandAt(1); }
virtual HValue* Canonicalize();
virtual void PrintDataTo(StringStream* stream);
virtual Representation RequiredInputRepresentation(int index) {
......
......@@ -5789,38 +5789,68 @@ Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
Expression* sub_expr,
HTypeof* typeof_expr,
Handle<String> check) {
CHECK_ALIVE(VisitForTypeOf(sub_expr));
HValue* value = Pop();
// Note: The HTypeof itself is removed during canonicalization, if possible.
HValue* value = typeof_expr->value();
HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check);
instr->set_position(expr->position());
return ast_context()->ReturnControl(instr, expr->id());
}
bool HGraphBuilder::TryLiteralCompare(CompareOperation* expr) {
Expression *sub_expr;
Handle<String> check;
if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
HandleLiteralCompareTypeof(expr, sub_expr, check);
static bool MatchLiteralCompareNil(HValue* left,
Token::Value op,
HValue* right,
Handle<Object> nil,
HValue** expr) {
if (left->IsConstant() &&
HConstant::cast(left)->handle().is_identical_to(nil) &&
Token::IsEqualityOp(op)) {
*expr = right;
return true;
}
return false;
}
if (expr->IsLiteralCompareUndefined(&sub_expr)) {
HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue);
return true;
}
if (expr->IsLiteralCompareNull(&sub_expr)) {
HandleLiteralCompareNil(expr, sub_expr, kNullValue);
static bool MatchLiteralCompareTypeof(HValue* left,
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 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) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
......@@ -5838,11 +5868,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
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);
// 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()) {
AddInstruction(new(zone()) HSoftDeoptimize);
current_block()->MarkAsDeoptimizing();
......@@ -5857,6 +5885,20 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
HValue* left = Pop();
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) {
// 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
......@@ -5945,13 +5987,11 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
void HGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
Expression* sub_expr,
HValue* value,
NilValue nil) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
CHECK_ALIVE(VisitForValue(sub_expr));
HValue* value = Pop();
EqualityKind kind =
expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality;
HIsNilAndBranch* instr = new(zone()) HIsNilAndBranch(value, kind, nil);
......
......@@ -912,12 +912,11 @@ class HGraphBuilder: public AstVisitor {
HValue* receiver,
SmallMapList* types,
Handle<String> name);
bool TryLiteralCompare(CompareOperation* expr);
void HandleLiteralCompareTypeof(CompareOperation* expr,
Expression* sub_expr,
HTypeof* typeof_expr,
Handle<String> check);
void HandleLiteralCompareNil(CompareOperation* expr,
Expression* sub_expr,
HValue* value,
NilValue nil);
HStringCharCodeAt* BuildStringCharCodeAt(HValue* context,
......
// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax
function typeofDirectly() {
return typeof({}) === "undefined";
}
typeofDirectly();
typeofDirectly();
%OptimizeFunctionOnNextCall(typeofDirectly);
typeofDirectly();
function typeofViaVariable() {
var foo = typeof({})
return foo === "undefined";
}
typeofViaVariable();
typeofViaVariable();
%OptimizeFunctionOnNextCall(typeofViaVariable);
typeofViaVariable();
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