OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 ExternalReference stack_guard_limit = | 497 ExternalReference stack_guard_limit = |
498 ExternalReference::address_of_stack_guard_limit(); | 498 ExternalReference::address_of_stack_guard_limit(); |
499 __ movq(kScratchRegister, stack_guard_limit); | 499 __ movq(kScratchRegister, stack_guard_limit); |
500 __ cmpq(rsp, Operand(kScratchRegister, 0)); | 500 __ cmpq(rsp, Operand(kScratchRegister, 0)); |
501 deferred->Branch(below); | 501 deferred->Branch(below); |
502 deferred->BindExit(); | 502 deferred->BindExit(); |
503 } | 503 } |
504 } | 504 } |
505 | 505 |
506 | 506 |
| 507 class CallFunctionStub: public CodeStub { |
| 508 public: |
| 509 CallFunctionStub(int argc, InLoopFlag in_loop) |
| 510 : argc_(argc), in_loop_(in_loop) { } |
| 511 |
| 512 void Generate(MacroAssembler* masm); |
| 513 |
| 514 private: |
| 515 int argc_; |
| 516 InLoopFlag in_loop_; |
| 517 |
| 518 #ifdef DEBUG |
| 519 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } |
| 520 #endif |
| 521 |
| 522 Major MajorKey() { return CallFunction; } |
| 523 int MinorKey() { return argc_; } |
| 524 InLoopFlag InLoop() { return in_loop_; } |
| 525 }; |
| 526 |
| 527 |
507 void CodeGenerator::VisitAndSpill(Statement* statement) { | 528 void CodeGenerator::VisitAndSpill(Statement* statement) { |
508 // TODO(X64): No architecture specific code. Move to shared location. | 529 // TODO(X64): No architecture specific code. Move to shared location. |
509 ASSERT(in_spilled_code()); | 530 ASSERT(in_spilled_code()); |
510 set_in_spilled_code(false); | 531 set_in_spilled_code(false); |
511 Visit(statement); | 532 Visit(statement); |
512 if (frame_ != NULL) { | 533 if (frame_ != NULL) { |
513 frame_->SpillAll(); | 534 frame_->SpillAll(); |
514 } | 535 } |
515 set_in_spilled_code(true); | 536 set_in_spilled_code(true); |
516 } | 537 } |
(...skipping 1961 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2478 | 2499 |
2479 // Pass the global proxy as the receiver. | 2500 // Pass the global proxy as the receiver. |
2480 LoadGlobalReceiver(); | 2501 LoadGlobalReceiver(); |
2481 | 2502 |
2482 // Call the function. | 2503 // Call the function. |
2483 CallWithArguments(args, node->position()); | 2504 CallWithArguments(args, node->position()); |
2484 } | 2505 } |
2485 } | 2506 } |
2486 | 2507 |
2487 | 2508 |
2488 void CodeGenerator::VisitCallEval(CallEval* a) { | 2509 void CodeGenerator::VisitCallEval(CallEval* node) { |
2489 UNIMPLEMENTED(); | 2510 Comment cmnt(masm_, "[ CallEval"); |
| 2511 |
| 2512 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve |
| 2513 // the function we need to call and the receiver of the call. |
| 2514 // Then we call the resolved function using the given arguments. |
| 2515 |
| 2516 ZoneList<Expression*>* args = node->arguments(); |
| 2517 Expression* function = node->expression(); |
| 2518 |
| 2519 CodeForStatementPosition(node); |
| 2520 |
| 2521 // Prepare the stack for the call to the resolved function. |
| 2522 Load(function); |
| 2523 |
| 2524 // Allocate a frame slot for the receiver. |
| 2525 frame_->Push(Factory::undefined_value()); |
| 2526 int arg_count = args->length(); |
| 2527 for (int i = 0; i < arg_count; i++) { |
| 2528 Load(args->at(i)); |
| 2529 } |
| 2530 |
| 2531 // Prepare the stack for the call to ResolvePossiblyDirectEval. |
| 2532 frame_->PushElementAt(arg_count + 1); |
| 2533 if (arg_count > 0) { |
| 2534 frame_->PushElementAt(arg_count); |
| 2535 } else { |
| 2536 frame_->Push(Factory::undefined_value()); |
| 2537 } |
| 2538 |
| 2539 // Resolve the call. |
| 2540 Result result = |
| 2541 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2); |
| 2542 |
| 2543 // Touch up the stack with the right values for the function and the |
| 2544 // receiver. Use a scratch register to avoid destroying the result. |
| 2545 Result scratch = allocator_->Allocate(); |
| 2546 ASSERT(scratch.is_valid()); |
| 2547 __ movl(scratch.reg(), |
| 2548 FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(0))); |
| 2549 frame_->SetElementAt(arg_count + 1, &scratch); |
| 2550 |
| 2551 // We can reuse the result register now. |
| 2552 frame_->Spill(result.reg()); |
| 2553 __ movl(result.reg(), |
| 2554 FieldOperand(result.reg(), FixedArray::OffsetOfElementAt(1))); |
| 2555 frame_->SetElementAt(arg_count, &result); |
| 2556 |
| 2557 // Call the function. |
| 2558 CodeForSourcePosition(node->position()); |
| 2559 InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; |
| 2560 CallFunctionStub call_function(arg_count, in_loop); |
| 2561 result = frame_->CallStub(&call_function, arg_count + 1); |
| 2562 |
| 2563 // Restore the context and overwrite the function on the stack with |
| 2564 // the result. |
| 2565 frame_->RestoreContextRegister(); |
| 2566 frame_->SetElementAt(0, &result); |
2490 } | 2567 } |
2491 | 2568 |
2492 | 2569 |
2493 void CodeGenerator::VisitCallNew(CallNew* node) { | 2570 void CodeGenerator::VisitCallNew(CallNew* node) { |
2494 Comment cmnt(masm_, "[ CallNew"); | 2571 Comment cmnt(masm_, "[ CallNew"); |
2495 CodeForStatementPosition(node); | 2572 CodeForStatementPosition(node); |
2496 | 2573 |
2497 // According to ECMA-262, section 11.2.2, page 44, the function | 2574 // According to ECMA-262, section 11.2.2, page 44, the function |
2498 // expression in new calls must be evaluated before the | 2575 // expression in new calls must be evaluated before the |
2499 // arguments. This is different from ordinary calls, where the | 2576 // arguments. This is different from ordinary calls, where the |
(...skipping 1235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3735 | 3812 |
3736 slow.Bind(); | 3813 slow.Bind(); |
3737 // A runtime call is inevitable. We eagerly sync frame elements | 3814 // A runtime call is inevitable. We eagerly sync frame elements |
3738 // to memory so that we can push the arguments directly into place | 3815 // to memory so that we can push the arguments directly into place |
3739 // on top of the frame. | 3816 // on top of the frame. |
3740 frame_->SyncRange(0, frame_->element_count() - 1); | 3817 frame_->SyncRange(0, frame_->element_count() - 1); |
3741 frame_->EmitPush(rsi); | 3818 frame_->EmitPush(rsi); |
3742 __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT); | 3819 __ movq(kScratchRegister, slot->var()->name(), RelocInfo::EMBEDDED_OBJECT); |
3743 frame_->EmitPush(kScratchRegister); | 3820 frame_->EmitPush(kScratchRegister); |
3744 if (typeof_state == INSIDE_TYPEOF) { | 3821 if (typeof_state == INSIDE_TYPEOF) { |
3745 // value = | 3822 value = |
3746 // frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3823 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
3747 } else { | 3824 } else { |
3748 // value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 3825 value = frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
3749 } | 3826 } |
3750 | 3827 |
3751 done.Bind(&value); | 3828 done.Bind(&value); |
3752 frame_->Push(&value); | 3829 frame_->Push(&value); |
3753 | 3830 |
3754 } else if (slot->var()->mode() == Variable::CONST) { | 3831 } else if (slot->var()->mode() == Variable::CONST) { |
3755 // Const slots may contain 'the hole' value (the constant hasn't been | 3832 // Const slots may contain 'the hole' value (the constant hasn't been |
3756 // initialized yet) which needs to be converted into the 'undefined' | 3833 // initialized yet) which needs to be converted into the 'undefined' |
3757 // value. | 3834 // value. |
3758 // | 3835 // |
(...skipping 1823 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5582 __ j(zero, label); | 5659 __ j(zero, label); |
5583 __ movq(kScratchRegister, FieldOperand(object, HeapObject::kMapOffset)); | 5660 __ movq(kScratchRegister, FieldOperand(object, HeapObject::kMapOffset)); |
5584 __ movzxbq(kScratchRegister, | 5661 __ movzxbq(kScratchRegister, |
5585 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); | 5662 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); |
5586 __ and_(kScratchRegister, Immediate(kIsSymbolMask | kIsNotStringMask)); | 5663 __ and_(kScratchRegister, Immediate(kIsSymbolMask | kIsNotStringMask)); |
5587 __ cmpb(kScratchRegister, Immediate(kSymbolTag | kStringTag)); | 5664 __ cmpb(kScratchRegister, Immediate(kSymbolTag | kStringTag)); |
5588 __ j(not_equal, label); | 5665 __ j(not_equal, label); |
5589 } | 5666 } |
5590 | 5667 |
5591 | 5668 |
5592 class CallFunctionStub: public CodeStub { | |
5593 public: | |
5594 CallFunctionStub(int argc, InLoopFlag in_loop) | |
5595 : argc_(argc), in_loop_(in_loop) { } | |
5596 | |
5597 void Generate(MacroAssembler* masm); | |
5598 | |
5599 private: | |
5600 int argc_; | |
5601 InLoopFlag in_loop_; | |
5602 | |
5603 #ifdef DEBUG | |
5604 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } | |
5605 #endif | |
5606 | |
5607 Major MajorKey() { return CallFunction; } | |
5608 int MinorKey() { return argc_; } | |
5609 InLoopFlag InLoop() { return in_loop_; } | |
5610 }; | |
5611 | |
5612 | |
5613 void CallFunctionStub::Generate(MacroAssembler* masm) { | |
5614 Label slow; | |
5615 | |
5616 // Get the function to call from the stack. | |
5617 // +2 ~ receiver, return address | |
5618 __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); | |
5619 | |
5620 // Check that the function really is a JavaScript function. | |
5621 __ testl(rdi, Immediate(kSmiTagMask)); | |
5622 __ j(zero, &slow); | |
5623 // Goto slow case if we do not have a function. | |
5624 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | |
5625 __ j(not_equal, &slow); | |
5626 | |
5627 // Fast-case: Just invoke the function. | |
5628 ParameterCount actual(argc_); | |
5629 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | |
5630 | |
5631 // Slow-case: Non-function called. | |
5632 __ bind(&slow); | |
5633 __ Set(rax, argc_); | |
5634 __ Set(rbx, 0); | |
5635 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); | |
5636 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); | |
5637 __ Jump(adaptor, RelocInfo::CODE_TARGET); | |
5638 } | |
5639 | |
5640 | |
5641 // Call the function just below TOS on the stack with the given | 5669 // Call the function just below TOS on the stack with the given |
5642 // arguments. The receiver is the TOS. | 5670 // arguments. The receiver is the TOS. |
5643 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 5671 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
5644 int position) { | 5672 int position) { |
5645 // Push the arguments ("left-to-right") on the stack. | 5673 // Push the arguments ("left-to-right") on the stack. |
5646 int arg_count = args->length(); | 5674 int arg_count = args->length(); |
5647 for (int i = 0; i < arg_count; i++) { | 5675 for (int i = 0; i < arg_count; i++) { |
5648 Load(args->at(i)); | 5676 Load(args->at(i)); |
5649 } | 5677 } |
5650 | 5678 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5684 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 5712 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
5685 __ movq(Operand(rsp, 1 * kPointerSize), rcx); | 5713 __ movq(Operand(rsp, 1 * kPointerSize), rcx); |
5686 __ lea(rdx, Operand(rdx, rcx, times_4, kDisplacement)); | 5714 __ lea(rdx, Operand(rdx, rcx, times_4, kDisplacement)); |
5687 __ movq(Operand(rsp, 2 * kPointerSize), rdx); | 5715 __ movq(Operand(rsp, 2 * kPointerSize), rdx); |
5688 | 5716 |
5689 // Do the runtime call to allocate the arguments object. | 5717 // Do the runtime call to allocate the arguments object. |
5690 __ bind(&runtime); | 5718 __ bind(&runtime); |
5691 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3); | 5719 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3); |
5692 } | 5720 } |
5693 | 5721 |
| 5722 |
5694 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { | 5723 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
5695 // The key is in rdx and the parameter count is in rax. | 5724 // The key is in rdx and the parameter count is in rax. |
5696 | 5725 |
5697 // The displacement is used for skipping the frame pointer on the | 5726 // The displacement is used for skipping the frame pointer on the |
5698 // stack. It is the offset of the last parameter (if any) relative | 5727 // stack. It is the offset of the last parameter (if any) relative |
5699 // to the frame pointer. | 5728 // to the frame pointer. |
5700 static const int kDisplacement = 1 * kPointerSize; | 5729 static const int kDisplacement = 1 * kPointerSize; |
5701 | 5730 |
5702 // Check that the key is a smi. | 5731 // Check that the key is a smi. |
5703 Label slow; | 5732 Label slow; |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5798 Label skip; | 5827 Label skip; |
5799 __ cmpq(rbp, Immediate(0)); | 5828 __ cmpq(rbp, Immediate(0)); |
5800 __ j(equal, &skip); | 5829 __ j(equal, &skip); |
5801 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 5830 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
5802 __ bind(&skip); | 5831 __ bind(&skip); |
5803 | 5832 |
5804 __ ret(0); | 5833 __ ret(0); |
5805 } | 5834 } |
5806 | 5835 |
5807 | 5836 |
5808 | |
5809 void CEntryStub::GenerateCore(MacroAssembler* masm, | 5837 void CEntryStub::GenerateCore(MacroAssembler* masm, |
5810 Label* throw_normal_exception, | 5838 Label* throw_normal_exception, |
5811 Label* throw_out_of_memory_exception, | 5839 Label* throw_out_of_memory_exception, |
5812 StackFrame::Type frame_type, | 5840 StackFrame::Type frame_type, |
5813 bool do_gc, | 5841 bool do_gc, |
5814 bool always_allocate_scope) { | 5842 bool always_allocate_scope) { |
5815 // rax: result parameter for PerformGC, if any. | 5843 // rax: result parameter for PerformGC, if any. |
5816 // rbx: pointer to C function (C callee-saved). | 5844 // rbx: pointer to C function (C callee-saved). |
5817 // rbp: frame pointer (restored after C call). | 5845 // rbp: frame pointer (restored after C call). |
5818 // rsp: stack pointer (restored after C call). | 5846 // rsp: stack pointer (restored after C call). |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5947 ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize, | 5975 ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize, |
5948 StackHandlerConstants::kStateOffset); | 5976 StackHandlerConstants::kStateOffset); |
5949 __ pop(rdx); // State | 5977 __ pop(rdx); // State |
5950 | 5978 |
5951 ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize, | 5979 ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize, |
5952 StackHandlerConstants::kPCOffset); | 5980 StackHandlerConstants::kPCOffset); |
5953 __ ret(0); | 5981 __ ret(0); |
5954 } | 5982 } |
5955 | 5983 |
5956 | 5984 |
| 5985 void CallFunctionStub::Generate(MacroAssembler* masm) { |
| 5986 Label slow; |
| 5987 |
| 5988 // Get the function to call from the stack. |
| 5989 // +2 ~ receiver, return address |
| 5990 __ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize)); |
| 5991 |
| 5992 // Check that the function really is a JavaScript function. |
| 5993 __ testl(rdi, Immediate(kSmiTagMask)); |
| 5994 __ j(zero, &slow); |
| 5995 // Goto slow case if we do not have a function. |
| 5996 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| 5997 __ j(not_equal, &slow); |
| 5998 |
| 5999 // Fast-case: Just invoke the function. |
| 6000 ParameterCount actual(argc_); |
| 6001 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); |
| 6002 |
| 6003 // Slow-case: Non-function called. |
| 6004 __ bind(&slow); |
| 6005 __ Set(rax, argc_); |
| 6006 __ Set(rbx, 0); |
| 6007 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); |
| 6008 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
| 6009 __ Jump(adaptor, RelocInfo::CODE_TARGET); |
| 6010 } |
| 6011 |
| 6012 |
5957 void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { | 6013 void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { |
5958 // rax: number of arguments including receiver | 6014 // rax: number of arguments including receiver |
5959 // rbx: pointer to C function (C callee-saved) | 6015 // rbx: pointer to C function (C callee-saved) |
5960 // rbp: frame pointer (restored after C call) | 6016 // rbp: frame pointer (restored after C call) |
5961 // rsp: stack pointer (restored after C call) | 6017 // rsp: stack pointer (restored after C call) |
5962 // rsi: current context (C callee-saved) | 6018 // rsi: current context (C callee-saved) |
5963 // rdi: caller's parameter pointer pp (C callee-saved) | 6019 // rdi: caller's parameter pointer pp (C callee-saved) |
5964 | 6020 |
5965 // NOTE: Invocations of builtins may return failure objects | 6021 // NOTE: Invocations of builtins may return failure objects |
5966 // instead of a proper result. The builtin entry handles | 6022 // instead of a proper result. The builtin entry handles |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6241 __ bind(&done_load_lhs); | 6297 __ bind(&done_load_lhs); |
6242 | 6298 |
6243 __ testl(rhs, Immediate(kSmiTagMask)); | 6299 __ testl(rhs, Immediate(kSmiTagMask)); |
6244 __ j(zero, &load_smi_rhs); | 6300 __ j(zero, &load_smi_rhs); |
6245 __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset)); | 6301 __ fld_d(FieldOperand(rhs, HeapNumber::kValueOffset)); |
6246 __ jmp(&done); | 6302 __ jmp(&done); |
6247 | 6303 |
6248 __ bind(&load_smi_lhs); | 6304 __ bind(&load_smi_lhs); |
6249 ASSERT(kSmiTagSize == 1); | 6305 ASSERT(kSmiTagSize == 1); |
6250 ASSERT(kSmiTag == 0); | 6306 ASSERT(kSmiTag == 0); |
6251 __ lea(kScratchRegister, Operand(lhs, lhs, times_1, 0); | 6307 __ lea(kScratchRegister, Operand(lhs, lhs, times_1, 0)); |
6252 __ push(kScratchRegister); | 6308 __ push(kScratchRegister); |
6253 __ fild_s(Operand(rsp, 0)); | 6309 __ fild_s(Operand(rsp, 0)); |
6254 __ pop(kScratchRegister); | 6310 __ pop(kScratchRegister); |
6255 __ jmp(&done_load_lhs); | 6311 __ jmp(&done_load_lhs); |
6256 | 6312 |
6257 __ bind(&load_smi_rhs); | 6313 __ bind(&load_smi_rhs); |
6258 __ movq(kScratchRegister, rhs); | 6314 __ movq(kScratchRegister, rhs); |
6259 __ sar(kScratchRegister, Immediate(kSmiTagSize)); | 6315 __ sar(kScratchRegister, Immediate(kSmiTagSize)); |
6260 __ push(kScratchRegister); | 6316 __ push(kScratchRegister); |
6261 __ fild_s(Operand(rsp, 0)); | 6317 __ fild_s(Operand(rsp, 0)); |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6700 break; | 6756 break; |
6701 default: | 6757 default: |
6702 UNREACHABLE(); | 6758 UNREACHABLE(); |
6703 } | 6759 } |
6704 } | 6760 } |
6705 | 6761 |
6706 | 6762 |
6707 #undef __ | 6763 #undef __ |
6708 | 6764 |
6709 } } // namespace v8::internal | 6765 } } // namespace v8::internal |
OLD | NEW |