OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_ARM64 | 5 #if V8_TARGET_ARCH_ARM64 |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 3726 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3737 SetExpressionPosition(expr); | 3737 SetExpressionPosition(expr); |
3738 | 3738 |
3739 // Evaluate yielded value first; the initial iterator definition depends on | 3739 // Evaluate yielded value first; the initial iterator definition depends on |
3740 // this. It stays on the stack while we update the iterator. | 3740 // this. It stays on the stack while we update the iterator. |
3741 VisitForStackValue(expr->expression()); | 3741 VisitForStackValue(expr->expression()); |
3742 | 3742 |
3743 // TODO(jbramley): Tidy this up once the merge is done, using named registers | 3743 // TODO(jbramley): Tidy this up once the merge is done, using named registers |
3744 // and suchlike. The implementation changes a little by bleeding_edge so I | 3744 // and suchlike. The implementation changes a little by bleeding_edge so I |
3745 // don't want to spend too much time on it now. | 3745 // don't want to spend too much time on it now. |
3746 | 3746 |
3747 Label suspend, continuation, post_runtime, resume; | 3747 Label suspend, continuation, post_runtime, resume, exception; |
3748 | 3748 |
3749 __ B(&suspend); | 3749 __ B(&suspend); |
3750 // TODO(jbramley): This label is bound here because the following code | 3750 // TODO(jbramley): This label is bound here because the following code |
3751 // looks at its pos(). Is it possible to do something more efficient here, | 3751 // looks at its pos(). Is it possible to do something more efficient here, |
3752 // perhaps using Adr? | 3752 // perhaps using Adr? |
3753 __ Bind(&continuation); | 3753 __ Bind(&continuation); |
3754 // When we arrive here, the stack top is the resume mode and | 3754 // When we arrive here, the stack top is the resume mode and |
3755 // result_register() holds the input value (the argument given to the | 3755 // result_register() holds the input value (the argument given to the |
3756 // respective resume operation). | 3756 // respective resume operation). |
3757 __ RecordGeneratorContinuation(); | 3757 __ RecordGeneratorContinuation(); |
3758 __ Pop(x1); | 3758 __ Pop(x1); |
3759 __ Cmp(x1, Smi::FromInt(JSGeneratorObject::RETURN)); | 3759 STATIC_ASSERT(JSGeneratorObject::kNext < JSGeneratorObject::kReturn); |
3760 __ B(ne, &resume); | 3760 STATIC_ASSERT(JSGeneratorObject::kThrow > JSGeneratorObject::kReturn); |
| 3761 __ Cmp(x1, Operand(Smi::FromInt(JSGeneratorObject::kReturn))); |
| 3762 __ B(lt, &resume); |
3761 __ Push(result_register()); | 3763 __ Push(result_register()); |
| 3764 __ B(gt, &exception); |
3762 EmitCreateIteratorResult(true); | 3765 EmitCreateIteratorResult(true); |
3763 EmitUnwindAndReturn(); | 3766 EmitUnwindAndReturn(); |
3764 | 3767 |
| 3768 __ Bind(&exception); |
| 3769 __ CallRuntime(Runtime::kThrow); |
| 3770 |
3765 __ Bind(&suspend); | 3771 __ Bind(&suspend); |
3766 OperandStackDepthIncrement(1); // Not popped on this path. | 3772 OperandStackDepthIncrement(1); // Not popped on this path. |
3767 VisitForAccumulatorValue(expr->generator_object()); | 3773 VisitForAccumulatorValue(expr->generator_object()); |
3768 DCHECK((continuation.pos() > 0) && Smi::IsValid(continuation.pos())); | 3774 DCHECK((continuation.pos() > 0) && Smi::IsValid(continuation.pos())); |
3769 __ Mov(x1, Smi::FromInt(continuation.pos())); | 3775 __ Mov(x1, Smi::FromInt(continuation.pos())); |
3770 __ Str(x1, FieldMemOperand(x0, JSGeneratorObject::kContinuationOffset)); | 3776 __ Str(x1, FieldMemOperand(x0, JSGeneratorObject::kContinuationOffset)); |
3771 __ Str(cp, FieldMemOperand(x0, JSGeneratorObject::kContextOffset)); | 3777 __ Str(cp, FieldMemOperand(x0, JSGeneratorObject::kContextOffset)); |
3772 __ Mov(x1, cp); | 3778 __ Mov(x1, cp); |
3773 __ RecordWriteField(x0, JSGeneratorObject::kContextOffset, x1, x2, | 3779 __ RecordWriteField(x0, JSGeneratorObject::kContextOffset, x1, x2, |
3774 kLRHasBeenSaved, kDontSaveFPRegs); | 3780 kLRHasBeenSaved, kDontSaveFPRegs); |
3775 __ Add(x1, fp, StandardFrameConstants::kExpressionsOffset); | 3781 __ Add(x1, fp, StandardFrameConstants::kExpressionsOffset); |
3776 __ Cmp(__ StackPointer(), x1); | 3782 __ Cmp(__ StackPointer(), x1); |
3777 __ B(eq, &post_runtime); | 3783 __ B(eq, &post_runtime); |
3778 __ Push(x0); // generator object | 3784 __ Push(x0); // generator object |
3779 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 3785 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
3780 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 3786 __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
3781 __ Bind(&post_runtime); | 3787 __ Bind(&post_runtime); |
3782 PopOperand(result_register()); | 3788 PopOperand(result_register()); |
3783 EmitReturnSequence(); | 3789 EmitReturnSequence(); |
3784 | 3790 |
3785 __ Bind(&resume); | 3791 __ Bind(&resume); |
3786 context()->Plug(result_register()); | 3792 context()->Plug(result_register()); |
3787 } | 3793 } |
3788 | 3794 |
3789 | |
3790 void FullCodeGenerator::EmitGeneratorResume(Expression *generator, | |
3791 Expression *value, | |
3792 JSGeneratorObject::ResumeMode resume_mode) { | |
3793 ASM_LOCATION("FullCodeGenerator::EmitGeneratorResume"); | |
3794 Register generator_object = x1; | |
3795 Register the_hole = x2; | |
3796 Register operand_stack_size = w3; | |
3797 Register function = x4; | |
3798 | |
3799 // The value stays in x0, and is ultimately read by the resumed generator, as | |
3800 // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it | |
3801 // is read to throw the value when the resumed generator is already closed. x1 | |
3802 // will hold the generator object until the activation has been resumed. | |
3803 VisitForStackValue(generator); | |
3804 VisitForAccumulatorValue(value); | |
3805 PopOperand(generator_object); | |
3806 | |
3807 // Store input value into generator object. | |
3808 __ Str(result_register(), | |
3809 FieldMemOperand(x1, JSGeneratorObject::kInputOffset)); | |
3810 __ Mov(x2, result_register()); | |
3811 __ RecordWriteField(x1, JSGeneratorObject::kInputOffset, x2, x3, | |
3812 kLRHasBeenSaved, kDontSaveFPRegs); | |
3813 | |
3814 // Load suspended function and context. | |
3815 __ Ldr(cp, FieldMemOperand(generator_object, | |
3816 JSGeneratorObject::kContextOffset)); | |
3817 __ Ldr(function, FieldMemOperand(generator_object, | |
3818 JSGeneratorObject::kFunctionOffset)); | |
3819 | |
3820 // Load receiver and store as the first argument. | |
3821 __ Ldr(x10, FieldMemOperand(generator_object, | |
3822 JSGeneratorObject::kReceiverOffset)); | |
3823 __ Push(x10); | |
3824 | |
3825 // Push holes for arguments to generator function. Since the parser forced | |
3826 // context allocation for any variables in generators, the actual argument | |
3827 // values have already been copied into the context and these dummy values | |
3828 // will never be used. | |
3829 __ Ldr(x10, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); | |
3830 | |
3831 // The number of arguments is stored as an int32_t, and -1 is a marker | |
3832 // (SharedFunctionInfo::kDontAdaptArgumentsSentinel), so we need sign | |
3833 // extension to correctly handle it. However, in this case, we operate on | |
3834 // 32-bit W registers, so extension isn't required. | |
3835 __ Ldr(w10, FieldMemOperand(x10, | |
3836 SharedFunctionInfo::kFormalParameterCountOffset)); | |
3837 __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex); | |
3838 __ PushMultipleTimes(the_hole, w10); | |
3839 | |
3840 // Enter a new JavaScript frame, and initialize its slots as they were when | |
3841 // the generator was suspended. | |
3842 Label resume_frame, done; | |
3843 __ Bl(&resume_frame); | |
3844 __ B(&done); | |
3845 | |
3846 __ Bind(&resume_frame); | |
3847 __ Push(lr, // Return address. | |
3848 fp, // Caller's frame pointer. | |
3849 cp, // Callee's context. | |
3850 function); // Callee's JS Function. | |
3851 __ Add(fp, __ StackPointer(), kPointerSize * 2); | |
3852 | |
3853 // Load and untag the operand stack size. | |
3854 __ Ldr(x10, FieldMemOperand(generator_object, | |
3855 JSGeneratorObject::kOperandStackOffset)); | |
3856 __ Ldr(operand_stack_size, | |
3857 UntagSmiFieldMemOperand(x10, FixedArray::kLengthOffset)); | |
3858 | |
3859 // If we are sending a value and there is no operand stack, we can jump back | |
3860 // in directly. | |
3861 if (resume_mode == JSGeneratorObject::NEXT) { | |
3862 Label slow_resume; | |
3863 __ Cbnz(operand_stack_size, &slow_resume); | |
3864 __ Ldr(x10, FieldMemOperand(function, JSFunction::kCodeEntryOffset)); | |
3865 __ Ldrsw(x11, | |
3866 UntagSmiFieldMemOperand(generator_object, | |
3867 JSGeneratorObject::kContinuationOffset)); | |
3868 __ Add(x10, x10, x11); | |
3869 __ Mov(x12, Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)); | |
3870 __ Str(x12, FieldMemOperand(generator_object, | |
3871 JSGeneratorObject::kContinuationOffset)); | |
3872 __ Push(Smi::FromInt(resume_mode)); // Consumed in continuation. | |
3873 __ Br(x10); | |
3874 | |
3875 __ Bind(&slow_resume); | |
3876 } | |
3877 | |
3878 // Otherwise, we push holes for the operand stack and call the runtime to fix | |
3879 // up the stack and the handlers. | |
3880 __ PushMultipleTimes(the_hole, operand_stack_size); | |
3881 | |
3882 __ Mov(x10, Smi::FromInt(resume_mode)); | |
3883 __ Push(Smi::FromInt(resume_mode)); // Consumed in continuation. | |
3884 __ Push(generator_object, result_register(), x10); | |
3885 __ CallRuntime(Runtime::kResumeJSGeneratorObject); | |
3886 // Not reached: the runtime call returns elsewhere. | |
3887 __ Unreachable(); | |
3888 | |
3889 __ Bind(&done); | |
3890 context()->Plug(result_register()); | |
3891 } | |
3892 | |
3893 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) { | 3795 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) { |
3894 OperandStackDepthIncrement(2); | 3796 OperandStackDepthIncrement(2); |
3895 __ Push(reg1, reg2); | 3797 __ Push(reg1, reg2); |
3896 } | 3798 } |
3897 | 3799 |
3898 void FullCodeGenerator::PushOperands(Register reg1, Register reg2, | 3800 void FullCodeGenerator::PushOperands(Register reg1, Register reg2, |
3899 Register reg3) { | 3801 Register reg3) { |
3900 OperandStackDepthIncrement(3); | 3802 OperandStackDepthIncrement(3); |
3901 __ Push(reg1, reg2, reg3); | 3803 __ Push(reg1, reg2, reg3); |
3902 } | 3804 } |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4153 } | 4055 } |
4154 | 4056 |
4155 return INTERRUPT; | 4057 return INTERRUPT; |
4156 } | 4058 } |
4157 | 4059 |
4158 | 4060 |
4159 } // namespace internal | 4061 } // namespace internal |
4160 } // namespace v8 | 4062 } // namespace v8 |
4161 | 4063 |
4162 #endif // V8_TARGET_ARCH_ARM64 | 4064 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |