606
604
// -- rdx : receiver
607
605
// -- rsp[0] : return address
608
606
// -----------------------------------
609
Label slow, slow_with_tagged_index, fast, array, extra;
607
Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double;
608
Label fast_object_with_map_check, fast_object_without_map_check;
609
Label fast_double_with_map_check, fast_double_without_map_check;
611
611
// Check that the object isn't a smi.
612
612
__ JumpIfSmi(rdx, &slow_with_tagged_index);
613
613
// Get the map from the receiver.
614
__ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
614
__ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
615
615
// Check that the receiver does not require access checks. We need
616
616
// to do this because this generic stub does not perform map checks.
617
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
617
__ testb(FieldOperand(r9, Map::kBitFieldOffset),
618
618
Immediate(1 << Map::kIsAccessCheckNeeded));
619
619
__ j(not_zero, &slow_with_tagged_index);
620
620
// Check that the key is a smi.
621
621
__ JumpIfNotSmi(rcx, &slow_with_tagged_index);
622
622
__ SmiToInteger32(rcx, rcx);
624
__ CmpInstanceType(rbx, JS_ARRAY_TYPE);
624
__ CmpInstanceType(r9, JS_ARRAY_TYPE);
625
625
__ j(equal, &array);
626
626
// Check that the object is some kind of JSObject.
627
__ CmpInstanceType(rbx, FIRST_JS_RECEIVER_TYPE);
627
__ CmpInstanceType(r9, FIRST_JS_OBJECT_TYPE);
628
628
__ j(below, &slow);
629
__ CmpInstanceType(rbx, JS_PROXY_TYPE);
631
__ CmpInstanceType(rbx, JS_FUNCTION_PROXY_TYPE);
634
630
// Object case: Check key against length in the elements array.
638
634
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
639
// Check that the object is in fast mode and writable.
640
__ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
641
Heap::kFixedArrayMapRootIndex);
642
__ j(not_equal, &slow);
635
// Check array bounds.
643
636
__ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
645
638
// rbx: FixedArray
640
__ j(above, &fast_object_with_map_check);
649
642
// Slow case: call runtime.
666
659
__ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
667
660
__ j(below_equal, &slow);
668
661
// Increment index to get new length.
669
__ leal(rdi, Operand(rcx, 1));
670
__ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
662
__ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
663
__ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
664
__ j(not_equal, &check_extra_double);
665
__ leal(rdi, Operand(rcx, 1));
666
__ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
667
__ jmp(&fast_object_without_map_check);
669
__ bind(&check_extra_double);
670
// rdi: elements array's map
671
__ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
672
__ j(not_equal, &slow);
673
__ leal(rdi, Operand(rcx, 1));
674
__ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
675
__ jmp(&fast_double_without_map_check);
673
677
// Array case: Get the length and the elements array from the JS
674
678
// array. Check that the array is in fast mode (and writable); if it
678
682
// rdx: receiver (a JSArray)
680
684
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
681
__ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
682
Heap::kFixedArrayMapRootIndex);
683
__ j(not_equal, &slow);
685
686
// Check the key against the length in the array, compute the
686
687
// address to store into and fall through to fast case.
688
689
__ j(below_equal, &extra);
690
691
// Fast case: Do the store.
692
__ bind(&fast_object_with_map_check);
693
694
// rbx: receiver's elements array (a FixedArray)
696
// rdx: receiver (a JSArray)
697
__ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
698
__ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
699
__ j(not_equal, &fast_double_with_map_check);
700
__ bind(&fast_object_without_map_check);
701
// Smi stores don't require further checks.
695
702
Label non_smi_value;
703
__ JumpIfNotSmi(rax, &non_smi_value);
704
// It's irrelevant whether array is smi-only or not when writing a smi.
696
705
__ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
698
__ JumpIfNotSmi(rax, &non_smi_value, Label::kNear);
700
709
__ bind(&non_smi_value);
701
// Slow case that needs to retain rcx for use by RecordWrite.
702
// Update write barrier for the elements array address.
704
__ RecordWriteNonSmi(rbx, 0, rdx, rcx);
710
// Writing a non-smi, check whether array allows non-smi elements.
711
// r9: receiver's map
712
__ CheckFastObjectElements(r9, &slow, Label::kNear);
713
__ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
715
__ movq(rdx, rax); // Preserve the value which is returned.
717
rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
720
__ bind(&fast_double_with_map_check);
721
// Check for fast double array case. If this fails, call through to the
723
// rdi: elements array's map
724
__ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
725
__ j(not_equal, &slow);
726
__ bind(&fast_double_without_map_check);
727
// If the value is a number, store it as a double in the FastDoubleElements
729
__ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0, &slow);
709
734
// The generated code does not accept smi keys.
710
735
// The generated code falls through if both probes miss.
711
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
714
Code::ExtraICState extra_ic_state) {
736
void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
739
Code::ExtraICState extra_state) {
715
740
// ----------- S t a t e -------------
716
741
// rcx : function name
717
742
// rdx : receiver
846
871
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
848
873
// Enter an internal frame.
849
__ EnterInternalFrame();
851
// Push the receiver and the name of the function.
858
__ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
861
// Move result to rdi and exit the internal frame.
863
__ LeaveInternalFrame();
875
FrameScope scope(masm, StackFrame::INTERNAL);
877
// Push the receiver and the name of the function.
884
__ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
887
// Move result to rdi and exit the internal frame.
865
891
// Check if the receiver is a global object of some sort.
866
892
// This can happen only for regular CallIC but not KeyedCallIC.
916
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
917
// ----------- S t a t e -------------
918
// rcx : function name
919
// rsp[0] : return address
920
// rsp[8] : argument argc
921
// rsp[16] : argument argc - 1
923
// rsp[argc * 8] : argument 1
924
// rsp[(argc + 1) * 8] : argument 0 = receiver
925
// -----------------------------------
927
GenerateCallNormal(masm, argc);
928
GenerateMiss(masm, argc, Code::kNoExtraICState);
932
void CallIC::GenerateMiss(MacroAssembler* masm,
934
Code::ExtraICState extra_ic_state) {
935
// ----------- S t a t e -------------
936
// rcx : function name
937
// rsp[0] : return address
938
// rsp[8] : argument argc
939
// rsp[16] : argument argc - 1
941
// rsp[argc * 8] : argument 1
942
// rsp[(argc + 1) * 8] : argument 0 = receiver
943
// -----------------------------------
945
GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
949
942
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
950
943
// ----------- S t a t e -------------
951
944
// rcx : function name
1002
995
// This branch is taken when calling KeyedCallIC_Miss is neither required
1003
996
// nor beneficial.
1004
997
__ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
1005
__ EnterInternalFrame();
1006
__ push(rcx); // save the key
1007
__ push(rdx); // pass the receiver
1008
__ push(rcx); // pass the key
1009
__ CallRuntime(Runtime::kKeyedGetProperty, 2);
1010
__ pop(rcx); // restore the key
1011
__ LeaveInternalFrame();
999
FrameScope scope(masm, StackFrame::INTERNAL);
1000
__ push(rcx); // save the key
1001
__ push(rdx); // pass the receiver
1002
__ push(rcx); // pass the key
1003
__ CallRuntime(Runtime::kKeyedGetProperty, 2);
1004
__ pop(rcx); // restore the key
1012
1006
__ movq(rdi, rax);
1013
1007
__ jmp(&do_call);
1072
1066
__ JumpIfSmi(rcx, &miss);
1073
1067
Condition cond = masm->IsObjectStringType(rcx, rax, rax);
1074
1068
__ j(NegateCondition(cond), &miss);
1075
GenerateCallNormal(masm, argc);
1069
CallICBase::GenerateNormal(masm, argc);
1076
1070
__ bind(&miss);
1077
1071
GenerateMiss(masm, argc);
1081
void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1082
// ----------- S t a t e -------------
1083
// rcx : function name
1084
// rsp[0] : return address
1085
// rsp[8] : argument argc
1086
// rsp[16] : argument argc - 1
1088
// rsp[argc * 8] : argument 1
1089
// rsp[(argc + 1) * 8] : argument 0 = receiver
1090
// -----------------------------------
1092
GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
1096
1075
static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
1097
1076
Register object,
1554
void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1555
// ----------- S t a t e -------------
1556
// -- rbx : target map
1557
// -- rdx : receiver
1558
// -- rsp[0] : return address
1559
// -----------------------------------
1560
// Must return the modified receiver in eax.
1561
if (!FLAG_trace_elements_transitions) {
1563
ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
1571
__ push(rbx); // return address
1572
__ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1576
void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1577
MacroAssembler* masm) {
1578
// ----------- S t a t e -------------
1579
// -- rbx : target map
1580
// -- rdx : receiver
1581
// -- rsp[0] : return address
1582
// -----------------------------------
1583
// Must return the modified receiver in eax.
1584
if (!FLAG_trace_elements_transitions) {
1586
ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
1594
__ push(rbx); // return address
1595
__ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);