Commit 628a2e2a authored by keuchel@chromium.org's avatar keuchel@chromium.org

Better codegen for '<expression> === void <literal>'.

Detect the pattern in both, the full compiler and crankshaft and generate direct pointer
comparisons. Along the way I cleaned up 'typeof <expression> == <string literal>' comparisons
as well by lifting platform independent code and checking the symmetric case.

BUG=v8:1440
TEST=cctest/test-api.cc

Review URL: http://codereview.chromium.org/7216008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8420 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 22abf6a5
......@@ -3964,25 +3964,13 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
}
bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
Expression* left,
Expression* right,
Label* if_true,
Label* if_false,
Label* fall_through) {
if (op != Token::EQ && op != Token::EQ_STRICT) return false;
// Check for the pattern: typeof <expression> == <string literal>.
Literal* right_literal = right->AsLiteral();
if (right_literal == NULL) return false;
Handle<Object> right_literal_value = right_literal->handle();
if (!right_literal_value->IsString()) return false;
UnaryOperation* left_unary = left->AsUnaryOperation();
if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
Handle<String> check = Handle<String>::cast(right_literal_value);
void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Handle<String> check,
Label* if_true,
Label* if_false,
Label* fall_through) {
{ AccumulatorValueContext context(this);
VisitForTypeofValue(left_unary->expression());
VisitForTypeofValue(expr);
}
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
......@@ -4036,8 +4024,18 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
} else {
if (if_false != fall_through) __ jmp(if_false);
}
}
void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
Label* if_true,
Label* if_false,
Label* fall_through) {
VisitForAccumulatorValue(expr);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
return true;
__ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
Split(eq, if_true, if_false, fall_through);
}
......@@ -4057,14 +4055,12 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// First we try a fast inlined version of the compare when one of
// the operands is a literal.
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
context()->Plug(if_true, if_false);
return;
}
Token::Value op = expr->op();
VisitForStackValue(expr->left());
switch (op) {
case Token::IN:
......
......@@ -337,6 +337,59 @@ bool BinaryOperation::ResultOverwriteAllowed() {
}
bool CompareOperation::IsLiteralCompareTypeof(Expression** expr,
Handle<String>* check) {
if (op_ != Token::EQ && op_ != Token::EQ_STRICT) return false;
UnaryOperation* left_unary = left_->AsUnaryOperation();
UnaryOperation* right_unary = right_->AsUnaryOperation();
Literal* left_literal = left_->AsLiteral();
Literal* right_literal = right_->AsLiteral();
// Check for the pattern: typeof <expression> == <string literal>.
if (left_unary != NULL && left_unary->op() == Token::TYPEOF &&
right_literal != NULL && right_literal->handle()->IsString()) {
*expr = left_unary->expression();
*check = Handle<String>::cast(right_literal->handle());
return true;
}
// Check for the pattern: <string literal> == typeof <expression>.
if (right_unary != NULL && right_unary->op() == Token::TYPEOF &&
left_literal != NULL && left_literal->handle()->IsString()) {
*expr = right_unary->expression();
*check = Handle<String>::cast(left_literal->handle());
return true;
}
return false;
}
bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) {
if (op_ != Token::EQ_STRICT) return false;
UnaryOperation* left_unary = left_->AsUnaryOperation();
UnaryOperation* right_unary = right_->AsUnaryOperation();
// Check for the pattern: <expression> === void <literal>.
if (right_unary != NULL && right_unary->op() == Token::VOID &&
right_unary->expression()->AsLiteral() != NULL) {
*expr = left_;
return true;
}
// Check for the pattern: void <literal> === <expression>.
if (left_unary != NULL && left_unary->op() == Token::VOID &&
left_unary->expression()->AsLiteral() != NULL) {
*expr = right_;
return true;
}
return false;
}
// ----------------------------------------------------------------------------
// Inlining support
......
......@@ -1473,6 +1473,10 @@ class CompareOperation: public Expression {
bool IsSmiCompare() { return compare_type_ == SMI_ONLY; }
bool IsObjectCompare() { return compare_type_ == OBJECT_ONLY; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
bool IsLiteralCompareUndefined(Expression** expr);
private:
Token::Value op_;
Expression* left_;
......
......@@ -1290,6 +1290,26 @@ int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
}
bool FullCodeGenerator::TryLiteralCompare(CompareOperation* compare,
Label* if_true,
Label* if_false,
Label* fall_through) {
Expression *expr;
Handle<String> check;
if (compare->IsLiteralCompareTypeof(&expr, &check)) {
EmitLiteralCompareTypeof(expr, check, if_true, if_false, fall_through);
return true;
}
if (compare->IsLiteralCompareUndefined(&expr)) {
EmitLiteralCompareUndefined(expr, if_true, if_false, fall_through);
return true;
}
return false;
}
#undef __
......
......@@ -362,13 +362,26 @@ class FullCodeGenerator: public AstVisitor {
// Try to perform a comparison as a fast inlined literal compare if
// the operands allow it. Returns true if the compare operations
// has been matched and all code generated; false otherwise.
bool TryLiteralCompare(Token::Value op,
Expression* left,
Expression* right,
bool TryLiteralCompare(CompareOperation* compare,
Label* if_true,
Label* if_false,
Label* fall_through);
// Platform-specific code for comparing the type of a value with
// a given literal string.
void EmitLiteralCompareTypeof(Expression* expr,
Handle<String> check,
Label* if_true,
Label* if_false,
Label* fall_through);
// Platform-specific code for strict equality comparison with
// the undefined value.
void EmitLiteralCompareUndefined(Expression* expr,
Label* if_true,
Label* if_false,
Label* fall_through);
// Bailout support.
void PrepareForBailout(Expression* node, State state);
void PrepareForBailoutForId(int id, State state);
......
......@@ -5490,6 +5490,29 @@ Representation HGraphBuilder::ToRepresentation(TypeInfo info) {
}
void HGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* compare_expr,
Expression* expr,
Handle<String> check) {
CHECK_ALIVE(VisitForTypeOf(expr));
HValue* expr_value = Pop();
HInstruction* instr = new(zone()) HTypeofIs(expr_value, check);
instr->set_position(compare_expr->position());
ast_context()->ReturnInstruction(instr, compare_expr->id());
}
void HGraphBuilder::HandleLiteralCompareUndefined(
CompareOperation* compare_expr, Expression* expr) {
CHECK_ALIVE(VisitForValue(expr));
HValue* lhs = Pop();
HValue* rhs = graph()->GetConstantUndefined();
HInstruction* instr =
new(zone()) HCompareObjectEq(lhs, rhs);
instr->set_position(compare_expr->position());
ast_context()->ReturnInstruction(instr, compare_expr->id());
}
void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
......@@ -5506,18 +5529,16 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
return;
}
// Check for the pattern: typeof <expression> == <string literal>.
UnaryOperation* left_unary = expr->left()->AsUnaryOperation();
Literal* right_literal = expr->right()->AsLiteral();
if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) &&
left_unary != NULL && left_unary->op() == Token::TYPEOF &&
right_literal != NULL && right_literal->handle()->IsString()) {
CHECK_ALIVE(VisitForTypeOf(left_unary->expression()));
HValue* left = Pop();
HInstruction* instr = new(zone()) HTypeofIs(left,
Handle<String>::cast(right_literal->handle()));
instr->set_position(expr->position());
ast_context()->ReturnInstruction(instr, expr->id());
// Check for special cases that compare against literals.
Expression *sub_expr;
Handle<String> check;
if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
HandleLiteralCompareTypeof(expr, sub_expr, check);
return;
}
if (expr->IsLiteralCompareUndefined(&sub_expr)) {
HandleLiteralCompareUndefined(expr, sub_expr);
return;
}
......
......@@ -881,6 +881,11 @@ class HGraphBuilder: public AstVisitor {
HValue* receiver,
ZoneMapList* types,
Handle<String> name);
void HandleLiteralCompareTypeof(CompareOperation* compare_expr,
Expression* expr,
Handle<String> check);
void HandleLiteralCompareUndefined(CompareOperation* compare_expr,
Expression* expr);
HStringCharCodeAt* BuildStringCharCodeAt(HValue* string,
HValue* index);
......
......@@ -3930,25 +3930,13 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
}
bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
Expression* left,
Expression* right,
Label* if_true,
Label* if_false,
Label* fall_through) {
if (op != Token::EQ && op != Token::EQ_STRICT) return false;
// Check for the pattern: typeof <expression> == <string literal>.
Literal* right_literal = right->AsLiteral();
if (right_literal == NULL) return false;
Handle<Object> right_literal_value = right_literal->handle();
if (!right_literal_value->IsString()) return false;
UnaryOperation* left_unary = left->AsUnaryOperation();
if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
Handle<String> check = Handle<String>::cast(right_literal_value);
void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Handle<String> check,
Label* if_true,
Label* if_false,
Label* fall_through) {
{ AccumulatorValueContext context(this);
VisitForTypeofValue(left_unary->expression());
VisitForTypeofValue(expr);
}
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
......@@ -3998,8 +3986,18 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
} else {
if (if_false != fall_through) __ jmp(if_false);
}
}
void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
Label* if_true,
Label* if_false,
Label* fall_through) {
VisitForAccumulatorValue(expr);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
return true;
__ cmp(eax, isolate()->factory()->undefined_value());
Split(equal, if_true, if_false, fall_through);
}
......@@ -4019,14 +4017,12 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// First we try a fast inlined version of the compare when one of
// the operands is a literal.
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
context()->Plug(if_true, if_false);
return;
}
Token::Value op = expr->op();
VisitForStackValue(expr->left());
switch (expr->op()) {
case Token::IN:
......
......@@ -3907,25 +3907,13 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
}
bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
Expression* left,
Expression* right,
Label* if_true,
Label* if_false,
Label* fall_through) {
if (op != Token::EQ && op != Token::EQ_STRICT) return false;
// Check for the pattern: typeof <expression> == <string literal>.
Literal* right_literal = right->AsLiteral();
if (right_literal == NULL) return false;
Handle<Object> right_literal_value = right_literal->handle();
if (!right_literal_value->IsString()) return false;
UnaryOperation* left_unary = left->AsUnaryOperation();
if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
Handle<String> check = Handle<String>::cast(right_literal_value);
void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
Handle<String> check,
Label* if_true,
Label* if_false,
Label* fall_through) {
{ AccumulatorValueContext context(this);
VisitForTypeofValue(left_unary->expression());
VisitForTypeofValue(expr);
}
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
......@@ -3976,8 +3964,18 @@ bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
} else {
if (if_false != fall_through) __ jmp(if_false);
}
}
void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
Label* if_true,
Label* if_false,
Label* fall_through) {
VisitForAccumulatorValue(expr);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
return true;
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
Split(equal, if_true, if_false, fall_through);
}
......@@ -3996,14 +3994,12 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
// First we try a fast inlined version of the compare when one of
// the operands is a literal.
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
context()->Plug(if_true, if_false);
return;
}
Token::Value op = expr->op();
VisitForStackValue(expr->left());
switch (op) {
case Token::IN:
......
......@@ -3862,6 +3862,49 @@ THREADED_TEST(UndetectableObject) {
}
THREADED_TEST(VoidLiteral) {
v8::HandleScope scope;
LocalContext env;
Local<v8::FunctionTemplate> desc =
v8::FunctionTemplate::New(0, v8::Handle<Value>());
desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
Local<v8::Object> obj = desc->GetFunction()->NewInstance();
env->Global()->Set(v8_str("undetectable"), obj);
ExpectBoolean("undefined == void 0", true);
ExpectBoolean("undetectable == void 0", true);
ExpectBoolean("null == void 0", true);
ExpectBoolean("undefined === void 0", true);
ExpectBoolean("undetectable === void 0", false);
ExpectBoolean("null === void 0", false);
ExpectBoolean("void 0 == undefined", true);
ExpectBoolean("void 0 == undetectable", true);
ExpectBoolean("void 0 == null", true);
ExpectBoolean("void 0 === undefined", true);
ExpectBoolean("void 0 === undetectable", false);
ExpectBoolean("void 0 === null", false);
ExpectString("(function() {"
" try {"
" return x === void 0;"
" } catch(e) {"
" return e.toString();"
" }"
"})()",
"ReferenceError: x is not defined");
ExpectString("(function() {"
" try {"
" return void 0 === x;"
" } catch(e) {"
" return e.toString();"
" }"
"})()",
"ReferenceError: x is not defined");
}
THREADED_TEST(ExtensibleOnUndetectable) {
v8::HandleScope scope;
......
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