Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 2267) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -1434,10 +1434,164 @@ |
} |
-void CodeGenerator::VisitUnaryOperation(UnaryOperation* a) { |
- UNIMPLEMENTED(); |
+void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
+ // Note that because of NOT and an optimization in comparison of a typeof |
+ // expression to a literal string, this function can fail to leave a value |
+ // on top of the frame or in the cc register. |
+ Comment cmnt(masm_, "[ UnaryOperation"); |
+ |
+ Token::Value op = node->op(); |
+ |
+ if (op == Token::NOT) { |
+ // Swap the true and false targets but keep the same actual label |
+ // as the fall through. |
+ destination()->Invert(); |
+ LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, destination(), true); |
+ // Swap the labels back. |
+ destination()->Invert(); |
+ |
+ } else if (op == Token::DELETE) { |
+ Property* property = node->expression()->AsProperty(); |
+ if (property != NULL) { |
+ Load(property->obj()); |
+ Load(property->key()); |
+ Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); |
+ frame_->Push(&answer); |
+ return; |
+ } |
+ |
+ Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
+ if (variable != NULL) { |
+ Slot* slot = variable->slot(); |
+ if (variable->is_global()) { |
+ LoadGlobal(); |
+ frame_->Push(variable->name()); |
+ Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
+ CALL_FUNCTION, 2); |
+ frame_->Push(&answer); |
+ return; |
+ |
+ } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
+ // Call the runtime to look up the context holding the named |
+ // variable. Sync the virtual frame eagerly so we can push the |
+ // arguments directly into place. |
+ frame_->SyncRange(0, frame_->element_count() - 1); |
+ frame_->EmitPush(rsi); |
+ frame_->EmitPush(variable->name()); |
+ Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); |
+ ASSERT(context.is_register()); |
+ frame_->EmitPush(context.reg()); |
+ context.Unuse(); |
+ frame_->EmitPush(variable->name()); |
+ Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
+ CALL_FUNCTION, 2); |
+ frame_->Push(&answer); |
+ return; |
+ } |
+ |
+ // Default: Result of deleting non-global, not dynamically |
+ // introduced variables is false. |
+ frame_->Push(Factory::false_value()); |
+ |
+ } else { |
+ // Default: Result of deleting expressions is true. |
+ Load(node->expression()); // may have side-effects |
+ frame_->SetElementAt(0, Factory::true_value()); |
+ } |
+ |
+ } else if (op == Token::TYPEOF) { |
+ // Special case for loading the typeof expression; see comment on |
+ // LoadTypeofExpression(). |
+ LoadTypeofExpression(node->expression()); |
+ Result answer = frame_->CallRuntime(Runtime::kTypeof, 1); |
+ frame_->Push(&answer); |
+ |
+ } else if (op == Token::VOID) { |
+ Expression* expression = node->expression(); |
+ if (expression && expression->AsLiteral() && ( |
+ expression->AsLiteral()->IsTrue() || |
+ expression->AsLiteral()->IsFalse() || |
+ expression->AsLiteral()->handle()->IsNumber() || |
+ expression->AsLiteral()->handle()->IsString() || |
+ expression->AsLiteral()->handle()->IsJSRegExp() || |
+ expression->AsLiteral()->IsNull())) { |
+ // Omit evaluating the value of the primitive literal. |
+ // It will be discarded anyway, and can have no side effect. |
+ frame_->Push(Factory::undefined_value()); |
+ } else { |
+ Load(node->expression()); |
+ frame_->SetElementAt(0, Factory::undefined_value()); |
+ } |
+ |
+ } else { |
+ Load(node->expression()); |
+ switch (op) { |
+ case Token::NOT: |
+ case Token::DELETE: |
+ case Token::TYPEOF: |
+ UNREACHABLE(); // handled above |
+ break; |
+ |
+ case Token::SUB: { |
+ bool overwrite = |
+ (node->AsBinaryOperation() != NULL && |
+ node->AsBinaryOperation()->ResultOverwriteAllowed()); |
+ UnarySubStub stub(overwrite); |
+ // TODO(1222589): remove dependency of TOS being cached inside stub |
+ Result operand = frame_->Pop(); |
+ Result answer = frame_->CallStub(&stub, &operand); |
+ frame_->Push(&answer); |
+ break; |
+ } |
+ |
+ case Token::BIT_NOT: { |
+ // Smi check. |
+ JumpTarget smi_label; |
+ JumpTarget continue_label; |
+ Result operand = frame_->Pop(); |
+ operand.ToRegister(); |
+ __ testl(operand.reg(), Immediate(kSmiTagMask)); |
+ smi_label.Branch(zero, &operand); |
+ |
+ frame_->Push(&operand); // undo popping of TOS |
+ Result answer = frame_->InvokeBuiltin(Builtins::BIT_NOT, |
+ CALL_FUNCTION, 1); |
+ continue_label.Jump(&answer); |
+ smi_label.Bind(&answer); |
+ answer.ToRegister(); |
+ frame_->Spill(answer.reg()); |
+ __ not_(answer.reg()); |
+ // Remove inverted smi-tag. The mask is sign-extended to 64 bits. |
+ __ xor_(answer.reg(), Immediate(kSmiTagMask)); |
+ continue_label.Bind(&answer); |
+ frame_->Push(&answer); |
+ break; |
+ } |
+ |
+ case Token::ADD: { |
+ // Smi check. |
+ JumpTarget continue_label; |
+ Result operand = frame_->Pop(); |
+ operand.ToRegister(); |
+ __ testl(operand.reg(), Immediate(kSmiTagMask)); |
+ continue_label.Branch(zero, &operand, taken); |
+ |
+ frame_->Push(&operand); |
+ Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
+ CALL_FUNCTION, 1); |
+ |
+ continue_label.Bind(&answer); |
+ frame_->Push(&answer); |
+ break; |
+ } |
+ |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
} |
+ |
void CodeGenerator::VisitCountOperation(CountOperation* a) { |
UNIMPLEMENTED(); |
} |