summaryrefslogtreecommitdiff
path: root/deps/v8/src/x64/full-codegen-x64.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/x64/full-codegen-x64.cc')
-rw-r--r--deps/v8/src/x64/full-codegen-x64.cc942
1 files changed, 439 insertions, 503 deletions
diff --git a/deps/v8/src/x64/full-codegen-x64.cc b/deps/v8/src/x64/full-codegen-x64.cc
index 725cbb0c58..ccd0392a30 100644
--- a/deps/v8/src/x64/full-codegen-x64.cc
+++ b/deps/v8/src/x64/full-codegen-x64.cc
@@ -29,6 +29,7 @@
#if defined(V8_TARGET_ARCH_X64)
+#include "code-stubs.h"
#include "codegen-inl.h"
#include "compiler.h"
#include "debug.h"
@@ -229,6 +230,13 @@ void FullCodeGenerator::EmitReturnSequence() {
}
+FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
+ Token::Value op, Expression* left, Expression* right) {
+ ASSERT(ShouldInlineSmiCase(op));
+ return kNoConstants;
+}
+
+
void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
switch (context) {
case Expression::kUninitialized:
@@ -253,20 +261,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
if (!reg.is(result_register())) __ movq(result_register(), reg);
- DoTest(context);
- break;
-
- case Expression::kValueTest:
- case Expression::kTestValue:
- if (!reg.is(result_register())) __ movq(result_register(), reg);
- switch (location_) {
- case kAccumulator:
- break;
- case kStack:
- __ push(result_register());
- break;
- }
- DoTest(context);
+ DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@@ -295,20 +290,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
case Expression::kTest:
Move(result_register(), slot);
- DoTest(context);
- break;
-
- case Expression::kValueTest:
- case Expression::kTestValue:
- Move(result_register(), slot);
- switch (location_) {
- case kAccumulator:
- break;
- case kStack:
- __ push(result_register());
- break;
- }
- DoTest(context);
+ DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@@ -334,20 +316,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
case Expression::kTest:
__ Move(result_register(), lit->handle());
- DoTest(context);
- break;
-
- case Expression::kValueTest:
- case Expression::kTestValue:
- __ Move(result_register(), lit->handle());
- switch (location_) {
- case kAccumulator:
- break;
- case kStack:
- __ push(result_register());
- break;
- }
- DoTest(context);
+ DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@@ -374,20 +343,7 @@ void FullCodeGenerator::ApplyTOS(Expression::Context context) {
case Expression::kTest:
__ pop(result_register());
- DoTest(context);
- break;
-
- case Expression::kValueTest:
- case Expression::kTestValue:
- switch (location_) {
- case kAccumulator:
- __ pop(result_register());
- break;
- case kStack:
- __ movq(result_register(), Operand(rsp, 0));
- break;
- }
- DoTest(context);
+ DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@@ -422,56 +378,7 @@ void FullCodeGenerator::DropAndApply(int count,
case Expression::kTest:
__ Drop(count);
if (!reg.is(result_register())) __ movq(result_register(), reg);
- DoTest(context);
- break;
-
- case Expression::kValueTest:
- case Expression::kTestValue:
- switch (location_) {
- case kAccumulator:
- __ Drop(count);
- if (!reg.is(result_register())) __ movq(result_register(), reg);
- break;
- case kStack:
- if (count > 1) __ Drop(count - 1);
- __ movq(result_register(), reg);
- __ movq(Operand(rsp, 0), result_register());
- break;
- }
- DoTest(context);
- break;
- }
-}
-
-
-void FullCodeGenerator::PrepareTest(Label* materialize_true,
- Label* materialize_false,
- Label** if_true,
- Label** if_false) {
- switch (context_) {
- case Expression::kUninitialized:
- UNREACHABLE();
- break;
- case Expression::kEffect:
- // In an effect context, the true and the false case branch to the
- // same label.
- *if_true = *if_false = materialize_true;
- break;
- case Expression::kValue:
- *if_true = materialize_true;
- *if_false = materialize_false;
- break;
- case Expression::kTest:
- *if_true = true_label_;
- *if_false = false_label_;
- break;
- case Expression::kValueTest:
- *if_true = materialize_true;
- *if_false = false_label_;
- break;
- case Expression::kTestValue:
- *if_true = true_label_;
- *if_false = materialize_false;
+ DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@@ -512,32 +419,6 @@ void FullCodeGenerator::Apply(Expression::Context context,
case Expression::kTest:
break;
-
- case Expression::kValueTest:
- __ bind(materialize_true);
- switch (location_) {
- case kAccumulator:
- __ Move(result_register(), Factory::true_value());
- break;
- case kStack:
- __ Push(Factory::true_value());
- break;
- }
- __ jmp(true_label_);
- break;
-
- case Expression::kTestValue:
- __ bind(materialize_false);
- switch (location_) {
- case kAccumulator:
- __ Move(result_register(), Factory::false_value());
- break;
- case kStack:
- __ Push(Factory::false_value());
- break;
- }
- __ jmp(false_label_);
- break;
}
}
@@ -565,78 +446,19 @@ void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
break;
}
case Expression::kTest:
- __ jmp(flag ? true_label_ : false_label_);
- break;
- case Expression::kTestValue:
- switch (location_) {
- case kAccumulator:
- // If value is false it's needed.
- if (!flag) __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
- break;
- case kStack:
- // If value is false it's needed.
- if (!flag) __ PushRoot(Heap::kFalseValueRootIndex);
- break;
- }
- __ jmp(flag ? true_label_ : false_label_);
- break;
- case Expression::kValueTest:
- switch (location_) {
- case kAccumulator:
- // If value is true it's needed.
- if (flag) __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
- break;
- case kStack:
- // If value is true it's needed.
- if (flag) __ PushRoot(Heap::kTrueValueRootIndex);
- break;
+ if (flag) {
+ if (true_label_ != fall_through_) __ jmp(true_label_);
+ } else {
+ if (false_label_ != fall_through_) __ jmp(false_label_);
}
- __ jmp(flag ? true_label_ : false_label_);
break;
}
}
-void FullCodeGenerator::DoTest(Expression::Context context) {
- // The value to test is in the accumulator. If the value might be needed
- // on the stack (value/test and test/value contexts with a stack location
- // desired), then the value is already duplicated on the stack.
- ASSERT_NE(NULL, true_label_);
- ASSERT_NE(NULL, false_label_);
-
- // In value/test and test/value expression contexts with stack as the
- // desired location, there is already an extra value on the stack. Use a
- // label to discard it if unneeded.
- Label discard;
- Label* if_true = true_label_;
- Label* if_false = false_label_;
- switch (context) {
- case Expression::kUninitialized:
- case Expression::kEffect:
- case Expression::kValue:
- UNREACHABLE();
- case Expression::kTest:
- break;
- case Expression::kValueTest:
- switch (location_) {
- case kAccumulator:
- break;
- case kStack:
- if_false = &discard;
- break;
- }
- break;
- case Expression::kTestValue:
- switch (location_) {
- case kAccumulator:
- break;
- case kStack:
- if_true = &discard;
- break;
- }
- break;
- }
-
+void FullCodeGenerator::DoTest(Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
// Emit the inlined tests assumed by the stub.
__ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
__ j(equal, if_false);
@@ -650,83 +472,28 @@ void FullCodeGenerator::DoTest(Expression::Context context) {
Condition is_smi = masm_->CheckSmi(result_register());
__ j(is_smi, if_true);
- // Save a copy of the value if it may be needed and isn't already saved.
- switch (context) {
- case Expression::kUninitialized:
- case Expression::kEffect:
- case Expression::kValue:
- UNREACHABLE();
- case Expression::kTest:
- break;
- case Expression::kValueTest:
- switch (location_) {
- case kAccumulator:
- __ push(result_register());
- break;
- case kStack:
- break;
- }
- break;
- case Expression::kTestValue:
- switch (location_) {
- case kAccumulator:
- __ push(result_register());
- break;
- case kStack:
- break;
- }
- break;
- }
-
// Call the ToBoolean stub for all other cases.
ToBooleanStub stub;
__ push(result_register());
__ CallStub(&stub);
__ testq(rax, rax);
- // The stub returns nonzero for true. Complete based on the context.
- switch (context) {
- case Expression::kUninitialized:
- case Expression::kEffect:
- case Expression::kValue:
- UNREACHABLE();
-
- case Expression::kTest:
- __ j(not_zero, true_label_);
- __ jmp(false_label_);
- break;
+ // The stub returns nonzero for true.
+ Split(not_zero, if_true, if_false, fall_through);
+}
- case Expression::kValueTest:
- switch (location_) {
- case kAccumulator:
- __ j(zero, &discard);
- __ pop(result_register());
- __ jmp(true_label_);
- break;
- case kStack:
- __ j(not_zero, true_label_);
- break;
- }
- __ bind(&discard);
- __ Drop(1);
- __ jmp(false_label_);
- break;
- case Expression::kTestValue:
- switch (location_) {
- case kAccumulator:
- __ j(not_zero, &discard);
- __ pop(result_register());
- __ jmp(false_label_);
- break;
- case kStack:
- __ j(zero, false_label_);
- break;
- }
- __ bind(&discard);
- __ Drop(1);
- __ jmp(true_label_);
- break;
+void FullCodeGenerator::Split(Condition cc,
+ Label* if_true,
+ Label* if_false,
+ Label* fall_through) {
+ if (if_false == fall_through) {
+ __ j(cc, if_true);
+ } else if (if_true == fall_through) {
+ __ j(NegateCondition(cc), if_false);
+ } else {
+ __ j(cc, if_true);
+ __ jmp(if_false);
}
}
@@ -912,17 +679,18 @@ void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// Compile the label expression.
VisitForValue(clause->label(), kAccumulator);
- // Perform the comparison as if via '==='. The comparison stub expects
- // the smi vs. smi case to be handled before it is called.
- Label slow_case;
- __ movq(rdx, Operand(rsp, 0)); // Switch value.
- __ JumpIfNotBothSmi(rdx, rax, &slow_case);
- __ SmiCompare(rdx, rax);
- __ j(not_equal, &next_test);
- __ Drop(1); // Switch value is no longer needed.
- __ jmp(clause->body_target()->entry_label());
+ // Perform the comparison as if via '==='.
+ if (ShouldInlineSmiCase(Token::EQ_STRICT)) {
+ Label slow_case;
+ __ movq(rdx, Operand(rsp, 0)); // Switch value.
+ __ JumpIfNotBothSmi(rdx, rax, &slow_case);
+ __ SmiCompare(rdx, rax);
+ __ j(not_equal, &next_test);
+ __ Drop(1); // Switch value is no longer needed.
+ __ jmp(clause->body_target()->entry_label());
+ __ bind(&slow_case);
+ }
- __ bind(&slow_case);
CompareStub stub(equal, true);
__ CallStub(&stub);
__ testq(rax, rax);
@@ -1206,7 +974,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
__ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
int literal_offset =
- FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
+ FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ movq(rbx, FieldOperand(rcx, literal_offset));
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
__ j(not_equal, &materialized);
@@ -1330,12 +1098,18 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
__ push(FieldOperand(rbx, JSFunction::kLiteralsOffset));
__ Push(Smi::FromInt(expr->literal_index()));
__ Push(expr->constant_elements());
- if (expr->depth() > 1) {
+ if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
+ FastCloneShallowArrayStub stub(
+ FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
+ __ CallStub(&stub);
+ __ IncrementCounter(&Counters::cow_arrays_created_stub, 1);
+ } else if (expr->depth() > 1) {
__ CallRuntime(Runtime::kCreateArrayLiteral, 3);
- } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
+ } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
__ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
} else {
- FastCloneShallowArrayStub stub(length);
+ FastCloneShallowArrayStub stub(
+ FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
__ CallStub(&stub);
}
@@ -1389,10 +1163,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
// slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
LhsKind assign_type = VARIABLE;
- Property* prop = expr->target()->AsProperty();
- if (prop != NULL) {
- assign_type =
- (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+ Property* property = expr->target()->AsProperty();
+ if (property != NULL) {
+ assign_type = (property->key()->IsPropertyName())
+ ? NAMED_PROPERTY
+ : KEYED_PROPERTY;
}
// Evaluate LHS expression.
@@ -1403,57 +1178,70 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
case NAMED_PROPERTY:
if (expr->is_compound()) {
// We need the receiver both on the stack and in the accumulator.
- VisitForValue(prop->obj(), kAccumulator);
+ VisitForValue(property->obj(), kAccumulator);
__ push(result_register());
} else {
- VisitForValue(prop->obj(), kStack);
+ VisitForValue(property->obj(), kStack);
}
break;
case KEYED_PROPERTY:
if (expr->is_compound()) {
- VisitForValue(prop->obj(), kStack);
- VisitForValue(prop->key(), kAccumulator);
+ VisitForValue(property->obj(), kStack);
+ VisitForValue(property->key(), kAccumulator);
__ movq(rdx, Operand(rsp, 0));
__ push(rax);
} else {
- VisitForValue(prop->obj(), kStack);
- VisitForValue(prop->key(), kStack);
+ VisitForValue(property->obj(), kStack);
+ VisitForValue(property->key(), kStack);
}
break;
}
- // If we have a compound assignment: Get value of LHS expression and
- // store in on top of the stack.
if (expr->is_compound()) {
Location saved_location = location_;
- location_ = kStack;
+ location_ = kAccumulator;
switch (assign_type) {
case VARIABLE:
EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
Expression::kValue);
break;
case NAMED_PROPERTY:
- EmitNamedPropertyLoad(prop);
- __ push(result_register());
+ EmitNamedPropertyLoad(property);
break;
case KEYED_PROPERTY:
- EmitKeyedPropertyLoad(prop);
- __ push(result_register());
+ EmitKeyedPropertyLoad(property);
break;
}
- location_ = saved_location;
- }
- // Evaluate RHS expression.
- Expression* rhs = expr->value();
- VisitForValue(rhs, kAccumulator);
+ Token::Value op = expr->binary_op();
+ ConstantOperand constant = ShouldInlineSmiCase(op)
+ ? GetConstantOperand(op, expr->target(), expr->value())
+ : kNoConstants;
+ ASSERT(constant == kRightConstant || constant == kNoConstants);
+ if (constant == kNoConstants) {
+ __ push(rax); // Left operand goes on the stack.
+ VisitForValue(expr->value(), kAccumulator);
+ }
- // If we have a compound assignment: Apply operator.
- if (expr->is_compound()) {
- Location saved_location = location_;
- location_ = kAccumulator;
- EmitBinaryOp(expr->binary_op(), Expression::kValue);
+ OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
+ ? OVERWRITE_RIGHT
+ : NO_OVERWRITE;
+ SetSourcePosition(expr->position() + 1);
+ if (ShouldInlineSmiCase(op)) {
+ EmitInlineSmiBinaryOp(expr,
+ op,
+ Expression::kValue,
+ mode,
+ expr->target(),
+ expr->value(),
+ constant);
+ } else {
+ EmitBinaryOp(op, Expression::kValue, mode);
+ }
location_ = saved_location;
+
+ } else {
+ VisitForValue(expr->value(), kAccumulator);
}
// Record source position before possible IC call.
@@ -1494,13 +1282,85 @@ void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
}
+void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
+ Token::Value op,
+ Expression::Context context,
+ OverwriteMode mode,
+ Expression* left,
+ Expression* right,
+ ConstantOperand constant) {
+ ASSERT(constant == kNoConstants); // Only handled case.
+
+ // Do combined smi check of the operands. Left operand is on the
+ // stack (popped into rdx). Right operand is in rax but moved into
+ // rcx to make the shifts easier.
+ Label done, stub_call, smi_case;
+ __ pop(rdx);
+ __ movq(rcx, rax);
+ Condition smi = __ CheckBothSmi(rdx, rax);
+ __ j(smi, &smi_case);
+
+ __ bind(&stub_call);
+ GenericBinaryOpStub stub(op, mode, NO_SMI_CODE_IN_STUB, TypeInfo::Unknown());
+ if (stub.ArgsInRegistersSupported()) {
+ stub.GenerateCall(masm_, rdx, rcx);
+ } else {
+ __ push(rdx);
+ __ push(rcx);
+ __ CallStub(&stub);
+ }
+ __ jmp(&done);
+
+ __ bind(&smi_case);
+ switch (op) {
+ case Token::SAR:
+ __ SmiShiftArithmeticRight(rax, rdx, rcx);
+ break;
+ case Token::SHL:
+ __ SmiShiftLeft(rax, rdx, rcx);
+ break;
+ case Token::SHR:
+ __ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
+ break;
+ case Token::ADD:
+ __ SmiAdd(rax, rdx, rcx, &stub_call);
+ break;
+ case Token::SUB:
+ __ SmiSub(rax, rdx, rcx, &stub_call);
+ break;
+ case Token::MUL:
+ __ SmiMul(rax, rdx, rcx, &stub_call);
+ break;
+ case Token::BIT_OR:
+ __ SmiOr(rax, rdx, rcx);
+ break;
+ case Token::BIT_AND:
+ __ SmiAnd(rax, rdx, rcx);
+ break;
+ case Token::BIT_XOR:
+ __ SmiXor(rax, rdx, rcx);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+
+ __ bind(&done);
+ Apply(context, rax);
+}
+
+
void FullCodeGenerator::EmitBinaryOp(Token::Value op,
- Expression::Context context) {
- __ push(result_register());
- GenericBinaryOpStub stub(op,
- NO_OVERWRITE,
- NO_GENERIC_BINARY_FLAGS);
- __ CallStub(&stub);
+ Expression::Context context,
+ OverwriteMode mode) {
+ GenericBinaryOpStub stub(op, mode, NO_GENERIC_BINARY_FLAGS);
+ if (stub.ArgsInRegistersSupported()) {
+ __ pop(rdx);
+ stub.GenerateCall(masm_, rdx, rax);
+ } else {
+ __ push(result_register());
+ __ CallStub(&stub);
+ }
Apply(context, rax);
}
@@ -1923,11 +1783,11 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// According to ECMA-262, section 11.2.2, page 44, the function
// expression in new calls must be evaluated before the
// arguments.
- // Push function on the stack.
- VisitForValue(expr->expression(), kStack);
- // Push global object (receiver).
- __ push(CodeGenerator::GlobalObject());
+ // Push constructor on the stack. If it's not a function it's used as
+ // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
+ // ignored.
+ VisitForValue(expr->expression(), kStack);
// Push the arguments ("left-to-right") on the stack.
ZoneList<Expression*>* args = expr->arguments();
@@ -1940,16 +1800,13 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
// constructor invocation.
SetSourcePosition(expr->position());
- // Load function, arg_count into rdi and rax.
+ // Load function and argument count into rdi and rax.
__ Set(rax, arg_count);
- // Function is in rsp[arg_count + 1].
- __ movq(rdi, Operand(rsp, rax, times_pointer_size, kPointerSize));
+ __ movq(rdi, Operand(rsp, arg_count * kPointerSize));
Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
__ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
-
- // Replace function on TOS with result in rax, or pop it.
- DropAndApply(1, context_, rax);
+ Apply(context_, rax);
}
@@ -1961,7 +1818,9 @@ void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_true);
__ jmp(if_false);
@@ -1978,11 +1837,12 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
Condition positive_smi = __ CheckPositiveSmi(rax);
- __ j(positive_smi, if_true);
- __ jmp(if_false);
+ Split(positive_smi, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -1996,7 +1856,9 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CompareRoot(rax, Heap::kNullValueRootIndex);
@@ -2010,8 +1872,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
__ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE));
__ j(below, if_false);
__ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE));
- __ j(below_equal, if_true);
- __ jmp(if_false);
+ Split(below_equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2025,12 +1886,13 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
- __ j(above_equal, if_true);
- __ jmp(if_false);
+ Split(above_equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2044,14 +1906,15 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
- __ j(not_zero, if_true);
- __ jmp(if_false);
+ Split(not_zero, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2066,7 +1929,9 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
// Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
// used in a few functions in runtime.js which should not normally be hit by
@@ -2084,12 +1949,13 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
- __ j(equal, if_true);
- __ jmp(if_false);
+ Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2103,12 +1969,13 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
- __ j(equal, if_true);
- __ jmp(if_false);
+ Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2122,12 +1989,13 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
- __ j(equal, if_true);
- __ jmp(if_false);
+ Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2140,7 +2008,9 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
// Get the frame pointer for the calling frame.
__ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
@@ -2156,8 +2026,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
__ bind(&check_frame_marker);
__ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
Smi::FromInt(StackFrame::CONSTRUCT));
- __ j(equal, if_true);
- __ jmp(if_false);
+ Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2173,12 +2042,13 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
__ pop(rbx);
__ cmpq(rax, rbx);
- __ j(equal, if_true);
- __ jmp(if_false);
+ Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@@ -2187,8 +2057,8 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
- // ArgumentsAccessStub expects the key in edx and the formal
- // parameter count in eax.
+ // ArgumentsAccessStub expects the key in rdx and the formal
+ // parameter count in rax.
VisitForValue(args->at(0), kAccumulator);
__ movq(rdx, rax);
__ Move(rax, Smi::FromInt(scope()->num_parameters()));
@@ -2392,7 +2262,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
VisitForValue(args->at(0), kStack); // Load the object.
VisitForValue(args->at(1), kAccumulator); // Load the value.
- __ pop(rbx); // rax = value. ebx = object.
+ __ pop(rbx); // rax = value. rbx = object.
Label done;
// If the object is a smi, return the value.
@@ -2727,6 +2597,40 @@ void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
}
+void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 1);
+
+ VisitForValue(args->at(0), kAccumulator);
+
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ __ testl(FieldOperand(rax, String::kHashFieldOffset),
+ Immediate(String::kContainsCachedArrayIndexMask));
+ __ j(zero, if_true);
+ __ jmp(if_false);
+
+ Apply(context_, if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
+ ASSERT(args->length() == 1);
+
+ VisitForValue(args->at(0), kAccumulator);
+
+ __ movl(rax, FieldOperand(rax, String::kHashFieldOffset));
+ ASSERT(String::kHashShift >= kSmiTagSize);
+ __ IndexFromHash(rax, rax);
+
+ Apply(context_, rax);
+}
+
+
void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Handle<String> name = expr->name();
if (name->length() > 0 && name->Get(0) == '_') {
@@ -2826,19 +2730,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
break;
}
break;
- case Expression::kTestValue:
- // Value is false so it's needed.
- switch (location_) {
- case kAccumulator:
- __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
- break;
- case kStack:
- __ PushRoot(Heap::kUndefinedValueRootIndex);
- break;
- }
- // Fall through.
case Expression::kTest:
- case Expression::kValueTest:
__ jmp(false_label_);
break;
}
@@ -2850,42 +2742,18 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
-
+ Label* fall_through = NULL;
// Notice that the labels are swapped.
- PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
-
- VisitForControl(expr->expression(), if_true, if_false);
-
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_false, &if_true, &fall_through);
+ VisitForControl(expr->expression(), if_true, if_false, fall_through);
Apply(context_, if_false, if_true); // Labels swapped.
break;
}
case Token::TYPEOF: {
Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
- VariableProxy* proxy = expr->expression()->AsVariableProxy();
- if (proxy != NULL &&
- !proxy->var()->is_this() &&
- proxy->var()->is_global()) {
- Comment cmnt(masm_, "Global variable");
- __ Move(rcx, proxy->name());
- __ movq(rax, CodeGenerator::GlobalObject());
- Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
- // Use a regular load, not a contextual load, to avoid a reference
- // error.
- __ Call(ic, RelocInfo::CODE_TARGET);
- __ push(rax);
- } else if (proxy != NULL &&
- proxy->var()->slot() != NULL &&
- proxy->var()->slot()->type() == Slot::LOOKUP) {
- __ push(rsi);
- __ Push(proxy->name());
- __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
- __ push(rax);
- } else {
- // This expression cannot throw a reference error at the top level.
- VisitForValue(expr->expression(), kStack);
- }
-
+ VisitForTypeofValue(expr->expression(), kStack);
__ CallRuntime(Runtime::kTypeof, 1);
Apply(context_, rax);
break;
@@ -2906,9 +2774,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
case Token::SUB: {
Comment cmt(masm_, "[ UnaryOperation (SUB)");
- bool can_overwrite =
- (expr->expression()->AsBinaryOperation() != NULL &&
- expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
UnaryOverwriteMode overwrite =
can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
GenericUnaryOpStub stub(Token::SUB, overwrite);
@@ -2922,27 +2788,24 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
case Token::BIT_NOT: {
Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
- bool can_overwrite =
- (expr->expression()->AsBinaryOperation() != NULL &&
- expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
- UnaryOverwriteMode overwrite =
- can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
- GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
- // GenericUnaryOpStub expects the argument to be in the
- // accumulator register rax.
+ // The generic unary operation stub expects the argument to be
+ // in the accumulator register rax.
VisitForValue(expr->expression(), kAccumulator);
- // Avoid calling the stub for Smis.
- Label smi, done;
- Condition is_smi = masm_->CheckSmi(result_register());
- __ j(is_smi, &smi);
- // Non-smi: call stub leaving result in accumulator register.
+ Label done;
+ if (ShouldInlineSmiCase(expr->op())) {
+ Label call_stub;
+ __ JumpIfNotSmi(rax, &call_stub);
+ __ SmiNot(rax, rax);
+ __ jmp(&done);
+ __ bind(&call_stub);
+ }
+ bool overwrite = expr->expression()->ResultOverwriteAllowed();
+ UnaryOverwriteMode mode =
+ overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
+ GenericUnaryOpStub stub(Token::BIT_NOT, mode);
__ CallStub(&stub);
- __ jmp(&done);
- // Perform operation directly on Smis.
- __ bind(&smi);
- __ SmiNot(result_register(), result_register());
__ bind(&done);
- Apply(context_, result_register());
+ Apply(context_, rax);
break;
}
@@ -2954,6 +2817,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
Comment cmnt(masm_, "[ CountOperation");
+ SetSourcePosition(expr->position());
// Invalid left-hand-sides are rewritten to have a 'throw
// ReferenceError' as the left-hand side.
@@ -3019,8 +2883,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
break;
case Expression::kValue:
case Expression::kTest:
- case Expression::kValueTest:
- case Expression::kTestValue:
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
@@ -3041,7 +2903,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
// Inline smi case if we are in a loop.
Label stub_call, done;
- if (loop_depth() > 0) {
+ if (ShouldInlineSmiCase(expr->op())) {
if (expr->op() == Token::INC) {
__ SmiAddConstant(rax, rax, Smi::FromInt(1));
} else {
@@ -3124,83 +2986,144 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
-void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
- Comment cmnt(masm_, "[ BinaryOperation");
- switch (expr->op()) {
- case Token::COMMA:
- VisitForEffect(expr->left());
- Visit(expr->right());
- break;
-
- case Token::OR:
- case Token::AND:
- EmitLogicalOperation(expr);
- break;
-
- case Token::ADD:
- case Token::SUB:
- case Token::DIV:
- case Token::MOD:
- case Token::MUL:
- case Token::BIT_OR:
- case Token::BIT_AND:
- case Token::BIT_XOR:
- case Token::SHL:
- case Token::SHR:
- case Token::SAR:
- VisitForValue(expr->left(), kStack);
- VisitForValue(expr->right(), kAccumulator);
- EmitBinaryOp(expr->op(), context_);
- break;
-
- default:
- UNREACHABLE();
- }
-}
-
-void FullCodeGenerator::EmitNullCompare(bool strict,
- Register obj,
- Register null_const,
- Label* if_true,
- Label* if_false,
- Register scratch) {
- __ cmpq(obj, null_const);
- if (strict) {
- __ j(equal, if_true);
+void FullCodeGenerator::VisitForTypeofValue(Expression* expr, Location where) {
+ VariableProxy* proxy = expr->AsVariableProxy();
+ if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
+ Comment cmnt(masm_, "Global variable");
+ __ Move(rcx, proxy->name());
+ __ movq(rax, CodeGenerator::GlobalObject());
+ Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+ // Use a regular load, not a contextual load, to avoid a reference
+ // error.
+ __ Call(ic, RelocInfo::CODE_TARGET);
+ if (where == kStack) __ push(rax);
+ } else if (proxy != NULL &&
+ proxy->var()->slot() != NULL &&
+ proxy->var()->slot()->type() == Slot::LOOKUP) {
+ __ push(rsi);
+ __ Push(proxy->name());
+ __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
+ if (where == kStack) __ push(rax);
} else {
+ // This expression cannot throw a reference error at the top level.
+ VisitForValue(expr, where);
+ }
+}
+
+
+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);
+
+ VisitForTypeofValue(left_unary->expression(), kAccumulator);
+ if (check->Equals(Heap::number_symbol())) {
+ Condition is_smi = masm_->CheckSmi(rax);
+ __ j(is_smi, if_true);
+ __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset));
+ __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex);
+ Split(equal, if_true, if_false, fall_through);
+ } else if (check->Equals(Heap::string_symbol())) {
+ Condition is_smi = masm_->CheckSmi(rax);
+ __ j(is_smi, if_false);
+ // Check for undetectable objects => false.
+ __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ __ j(not_zero, if_false);
+ __ CmpInstanceType(rdx, FIRST_NONSTRING_TYPE);
+ Split(below, if_true, if_false, fall_through);
+ } else if (check->Equals(Heap::boolean_symbol())) {
+ __ CompareRoot(rax, Heap::kTrueValueRootIndex);
__ j(equal, if_true);
- __ CompareRoot(obj, Heap::kUndefinedValueRootIndex);
+ __ CompareRoot(rax, Heap::kFalseValueRootIndex);
+ Split(equal, if_true, if_false, fall_through);
+ } else if (check->Equals(Heap::undefined_symbol())) {
+ __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(equal, if_true);
- __ JumpIfSmi(obj, if_false);
- // It can be an undetectable object.
- __ movq(scratch, FieldOperand(obj, HeapObject::kMapOffset));
- __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
+ Condition is_smi = masm_->CheckSmi(rax);
+ __ j(is_smi, if_false);
+ // Check for undetectable objects => true.
+ __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ Split(not_zero, if_true, if_false, fall_through);
+ } else if (check->Equals(Heap::function_symbol())) {
+ Condition is_smi = masm_->CheckSmi(rax);
+ __ j(is_smi, if_false);
+ __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx);
+ __ j(equal, if_true);
+ // Regular expressions => 'function' (they are callable).
+ __ CmpInstanceType(rdx, JS_REGEXP_TYPE);
+ Split(equal, if_true, if_false, fall_through);
+ } else if (check->Equals(Heap::object_symbol())) {
+ Condition is_smi = masm_->CheckSmi(rax);
+ __ j(is_smi, if_false);
+ __ CompareRoot(rax, Heap::kNullValueRootIndex);
+ __ j(equal, if_true);
+ // Regular expressions => 'function', not 'object'.
+ __ CmpObjectType(rax, JS_REGEXP_TYPE, rdx);
+ __ j(equal, if_false);
+ // Check for undetectable objects => false.
+ __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
- __ j(not_zero, if_true);
+ __ j(not_zero, if_false);
+ // Check for JS objects => true.
+ __ CmpInstanceType(rdx, FIRST_JS_OBJECT_TYPE);
+ __ j(below, if_false);
+ __ CmpInstanceType(rdx, LAST_JS_OBJECT_TYPE);
+ Split(below_equal, if_true, if_false, fall_through);
+ } else {
+ if (if_false != fall_through) __ jmp(if_false);
}
- __ jmp(if_false);
+
+ return true;
}
void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Comment cmnt(masm_, "[ CompareOperation");
+ SetSourcePosition(expr->position());
// Always perform the comparison for its control flow. Pack the result
// into the expression's context after the comparison is performed.
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
- PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ // 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)) {
+ Apply(context_, if_true, if_false);
+ return;
+ }
VisitForValue(expr->left(), kStack);
- switch (expr->op()) {
+ switch (op) {
case Token::IN:
VisitForValue(expr->right(), kStack);
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
- __ j(equal, if_true);
- __ jmp(if_false);
+ Split(equal, if_true, if_false, fall_through);
break;
case Token::INSTANCEOF: {
@@ -3208,8 +3131,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
InstanceofStub stub;
__ CallStub(&stub);
__ testq(rax, rax);
- __ j(zero, if_true); // The stub returns 0 for true.
- __ jmp(if_false);
+ // The stub returns 0 for true.
+ Split(zero, if_true, if_false, fall_through);
break;
}
@@ -3217,28 +3140,14 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
VisitForValue(expr->right(), kAccumulator);
Condition cc = no_condition;
bool strict = false;
- switch (expr->op()) {
+ switch (op) {
case Token::EQ_STRICT:
strict = true;
// Fall through.
- case Token::EQ: {
+ case Token::EQ:
cc = equal;
__ pop(rdx);
- // If either operand is constant null we do a fast compare
- // against null.
- Literal* right_literal = expr->right()->AsLiteral();
- Literal* left_literal = expr->left()->AsLiteral();
- if (right_literal != NULL && right_literal->handle()->IsNull()) {
- EmitNullCompare(strict, rdx, rax, if_true, if_false, rcx);
- Apply(context_, if_true, if_false);
- return;
- } else if (left_literal != NULL && left_literal->handle()->IsNull()) {
- EmitNullCompare(strict, rax, rdx, if_true, if_false, rcx);
- Apply(context_, if_true, if_false);
- return;
- }
break;
- }
case Token::LT:
cc = less;
__ pop(rdx);
@@ -3265,20 +3174,18 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
UNREACHABLE();
}
- // The comparison stub expects the smi vs. smi case to be handled
- // before it is called.
- Label slow_case;
- __ JumpIfNotBothSmi(rax, rdx, &slow_case);
- __ SmiCompare(rdx, rax);
- __ j(cc, if_true);
- __ jmp(if_false);
+ if (ShouldInlineSmiCase(op)) {
+ Label slow_case;
+ __ JumpIfNotBothSmi(rax, rdx, &slow_case);
+ __ SmiCompare(rdx, rax);
+ Split(cc, if_true, if_false, NULL);
+ __ bind(&slow_case);
+ }
- __ bind(&slow_case);
CompareStub stub(cc, strict);
__ CallStub(&stub);
__ testq(rax, rax);
- __ j(cc, if_true);
- __ jmp(if_false);
+ Split(cc, if_true, if_false, fall_through);
}
}
@@ -3288,6 +3195,35 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
}
+void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
+ Comment cmnt(masm_, "[ CompareToNull");
+ Label materialize_true, materialize_false;
+ Label* if_true = NULL;
+ Label* if_false = NULL;
+ Label* fall_through = NULL;
+ PrepareTest(&materialize_true, &materialize_false,
+ &if_true, &if_false, &fall_through);
+
+ VisitForValue(expr->expression(), kAccumulator);
+ __ CompareRoot(rax, Heap::kNullValueRootIndex);
+ if (expr->is_strict()) {
+ Split(equal, if_true, if_false, fall_through);
+ } else {
+ __ j(equal, if_true);
+ __ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
+ __ j(equal, if_true);
+ Condition is_smi = masm_->CheckSmi(rax);
+ __ j(is_smi, if_false);
+ // It can be an undetectable object.
+ __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
+ __ testb(FieldOperand(rdx, Map::kBitFieldOffset),
+ Immediate(1 << Map::kIsUndetectable));
+ Split(not_zero, if_true, if_false, fall_through);
+ }
+ Apply(context_, if_true, if_false);
+}
+
+
void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
__ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
Apply(context_, rax);