Revision: 8420
Author: [email protected]
Date: Fri Jun 24 07:30:10 2011
Log: 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
http://code.google.com/p/v8/source/detail?r=8420
Modified:
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/ast.cc
/branches/bleeding_edge/src/ast.h
/branches/bleeding_edge/src/full-codegen.cc
/branches/bleeding_edge/src/full-codegen.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Jun 17 11:32:36
2011
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Fri Jun 24 07:30:10
2011
@@ -3964,25 +3964,13 @@
}
-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 @@
} else {
if (if_false != fall_through) __ jmp(if_false);
}
-
- return true;
+}
+
+
+void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
+ Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
+ VisitForAccumulatorValue(expr);
+ PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
+
+ __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
+ Split(eq, if_true, if_false, fall_through);
}
@@ -4057,14 +4055,12 @@
// 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:
=======================================
--- /branches/bleeding_edge/src/ast.cc Mon Jun 20 03:19:00 2011
+++ /branches/bleeding_edge/src/ast.cc Fri Jun 24 07:30:10 2011
@@ -335,6 +335,59 @@
}
return false;
}
+
+
+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;
+}
//
----------------------------------------------------------------------------
=======================================
--- /branches/bleeding_edge/src/ast.h Mon Jun 20 03:19:00 2011
+++ /branches/bleeding_edge/src/ast.h Fri Jun 24 07:30:10 2011
@@ -1472,6 +1472,10 @@
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
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_;
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Wed Jun 15 23:37:49 2011
+++ /branches/bleeding_edge/src/full-codegen.cc Fri Jun 24 07:30:10 2011
@@ -1288,6 +1288,26 @@
__ PopTryHandler();
return 0;
}
+
+
+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 __
=======================================
--- /branches/bleeding_edge/src/full-codegen.h Wed Jun 15 23:37:49 2011
+++ /branches/bleeding_edge/src/full-codegen.h Fri Jun 24 07:30:10 2011
@@ -362,13 +362,26 @@
// 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);
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Wed Jun 22 23:33:38 2011
+++ /branches/bleeding_edge/src/hydrogen.cc Fri Jun 24 07:30:10 2011
@@ -5488,6 +5488,29 @@
if (info.IsNumber()) return Representation::Double();
return Representation::Tagged();
}
+
+
+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) {
@@ -5506,18 +5529,16 @@
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;
}
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Wed Jun 22 23:26:50 2011
+++ /branches/bleeding_edge/src/hydrogen.h Fri Jun 24 07:30:10 2011
@@ -881,6 +881,11 @@
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);
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Wed Jun 22
01:28:35 2011
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Fri Jun 24
07:30:10 2011
@@ -3930,25 +3930,13 @@
}
-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 @@
} else {
if (if_false != fall_through) __ jmp(if_false);
}
-
- return true;
+}
+
+
+void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
+ Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
+ VisitForAccumulatorValue(expr);
+ PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
+
+ __ cmp(eax, isolate()->factory()->undefined_value());
+ Split(equal, if_true, if_false, fall_through);
}
@@ -4019,14 +4017,12 @@
// 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:
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Wed Jun 22 01:28:35
2011
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Fri Jun 24 07:30:10
2011
@@ -3907,25 +3907,13 @@
}
-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 @@
} else {
if (if_false != fall_through) __ jmp(if_false);
}
-
- return true;
+}
+
+
+void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
+ Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
+ VisitForAccumulatorValue(expr);
+ PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
+
+ __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
+ Split(equal, if_true, if_false, fall_through);
}
@@ -3996,14 +3994,12 @@
// 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:
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Thu Jun 23 01:28:23 2011
+++ /branches/bleeding_edge/test/cctest/test-api.cc Fri Jun 24 07:30:10 2011
@@ -3862,6 +3862,49 @@
}
+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;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev