Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Side by Side Diff: src/x64/stub-cache-x64.cc

Issue 2860049: Port prototype-call-stubs for normal objects (http://codereview.chromium.org/... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/macro-assembler-x64.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 __ j(not_equal, &miss); 74 __ j(not_equal, &miss);
75 75
76 // Jump to the first instruction in the code stub. 76 // Jump to the first instruction in the code stub.
77 __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag)); 77 __ addq(kScratchRegister, Immediate(Code::kHeaderSize - kHeapObjectTag));
78 __ jmp(kScratchRegister); 78 __ jmp(kScratchRegister);
79 79
80 __ bind(&miss); 80 __ bind(&miss);
81 } 81 }
82 82
83 83
84 // Helper function used to check that the dictionary doesn't contain
85 // the property. This function may return false negatives, so miss_label
86 // must always call a backup property check that is complete.
87 // This function is safe to call if the receiver has fast properties.
88 // Name must be a symbol and receiver must be a heap object.
89 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm,
90 Label* miss_label,
91 Register receiver,
92 String* name,
93 Register r0,
94 Register extra) {
95 ASSERT(name->IsSymbol());
96 __ IncrementCounter(&Counters::negative_lookups, 1);
97 __ IncrementCounter(&Counters::negative_lookups_miss, 1);
98
99 Label done;
100 __ movq(r0, FieldOperand(receiver, HeapObject::kMapOffset));
101
102 const int kInterceptorOrAccessCheckNeededMask =
103 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded);
104
105 // Bail out if the receiver has a named interceptor or requires access checks.
106 __ testb(FieldOperand(r0, Map::kBitFieldOffset),
107 Immediate(kInterceptorOrAccessCheckNeededMask));
108 __ j(not_zero, miss_label);
109
110 // Check that receiver is a JSObject.
111 __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE);
112 __ j(below, miss_label);
113
114 // Load properties array.
115 Register properties = r0;
116 __ movq(properties, FieldOperand(receiver, JSObject::kPropertiesOffset));
117
118 // Check that the properties array is a dictionary.
119 __ CompareRoot(FieldOperand(properties, HeapObject::kMapOffset),
120 Heap::kHashTableMapRootIndex);
121 __ j(not_equal, miss_label);
122
123 // Compute the capacity mask.
124 const int kCapacityOffset =
125 StringDictionary::kHeaderSize +
126 StringDictionary::kCapacityIndex * kPointerSize;
127
128 // Generate an unrolled loop that performs a few probes before
129 // giving up.
130 static const int kProbes = 4;
131 const int kElementsStartOffset =
132 StringDictionary::kHeaderSize +
133 StringDictionary::kElementsStartIndex * kPointerSize;
134
135 // If names of slots in range from 1 to kProbes - 1 for the hash value are
136 // not equal to the name and kProbes-th slot is not used (its name is the
137 // undefined value), it guarantees the hash table doesn't contain the
138 // property. It's true even if some slots represent deleted properties
139 // (their names are the null value).
140 for (int i = 0; i < kProbes; i++) {
141 // r0 points to properties hash.
142 // Compute the masked index: (hash + i + i * i) & mask.
143 if (extra.is(no_reg)) {
144 __ push(receiver);
145 }
146 Register index = extra.is(no_reg) ? receiver : extra;
147 // Capacity is smi 2^n.
148 __ SmiToInteger32(index, FieldOperand(properties, kCapacityOffset));
149 __ decl(index);
150 __ and_(index,
151 Immediate(name->Hash() + StringDictionary::GetProbeOffset(i)));
152
153 // Scale the index by multiplying by the entry size.
154 ASSERT(StringDictionary::kEntrySize == 3);
155 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3.
156
157 Register entity_name = extra.is(no_reg) ? properties : extra;
158 // Having undefined at this place means the name is not contained.
159 ASSERT_EQ(kSmiTagSize, 1);
160 __ movq(entity_name, Operand(properties, index, times_pointer_size,
161 kElementsStartOffset - kHeapObjectTag));
162 __ Cmp(entity_name, Factory::undefined_value());
163 if (extra.is(no_reg)) {
164 // 'receiver' shares a register with 'entity_name'.
165 __ pop(receiver);
166 }
167 // __ jmp(miss_label);
168 if (i != kProbes - 1) {
169 __ j(equal, &done);
170
171 // Stop if found the property.
172 __ Cmp(entity_name, Handle<String>(name));
173 __ j(equal, miss_label);
174
175 if (extra.is(no_reg)) {
176 // Restore the properties if their register was occupied by the name.
177 __ movq(properties,
178 FieldOperand(receiver, JSObject::kPropertiesOffset));
179 }
180 } else {
181 // Give up probing if still not found the undefined value.
182 __ j(not_equal, miss_label);
183 }
184 }
185
186 __ bind(&done);
187 __ DecrementCounter(&Counters::negative_lookups_miss, 1);
188 }
189
190
84 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { 191 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
85 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); 192 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
86 Code* code = NULL; 193 Code* code = NULL;
87 if (kind == Code::LOAD_IC) { 194 if (kind == Code::LOAD_IC) {
88 code = Builtins::builtin(Builtins::LoadIC_Miss); 195 code = Builtins::builtin(Builtins::LoadIC_Miss);
89 } else { 196 } else {
90 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss); 197 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss);
91 } 198 }
92 199
93 Handle<Code> ic(code); 200 Handle<Code> ic(code);
(...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after
777 JSObject::cast(object), holder); 884 JSObject::cast(object), holder);
778 } 885 }
779 886
780 if (depth != kInvalidProtoDepth) { 887 if (depth != kInvalidProtoDepth) {
781 __ IncrementCounter(&Counters::call_const_fast_api, 1); 888 __ IncrementCounter(&Counters::call_const_fast_api, 1);
782 ReserveSpaceForFastApiCall(masm(), rax); 889 ReserveSpaceForFastApiCall(masm(), rax);
783 } 890 }
784 891
785 // Check that the maps haven't changed. 892 // Check that the maps haven't changed.
786 CheckPrototypes(JSObject::cast(object), rdx, holder, 893 CheckPrototypes(JSObject::cast(object), rdx, holder,
787 rbx, rax, name, depth, &miss); 894 rbx, rax, name, depth, &miss, rdi);
788 895
789 // Patch the receiver on the stack with the global proxy if 896 // Patch the receiver on the stack with the global proxy if
790 // necessary. 897 // necessary.
791 if (object->IsGlobalObject()) { 898 if (object->IsGlobalObject()) {
792 ASSERT(depth == kInvalidProtoDepth); 899 ASSERT(depth == kInvalidProtoDepth);
793 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 900 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
794 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 901 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
795 } 902 }
796 break; 903 break;
797 904
798 case STRING_CHECK: 905 case STRING_CHECK:
799 if (!function->IsBuiltin()) { 906 if (!function->IsBuiltin()) {
800 // Calling non-builtins with a value as receiver requires boxing. 907 // Calling non-builtins with a value as receiver requires boxing.
801 __ jmp(&miss); 908 __ jmp(&miss);
802 } else { 909 } else {
803 // Check that the object is a two-byte string or a symbol. 910 // Check that the object is a two-byte string or a symbol.
804 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax); 911 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
805 __ j(above_equal, &miss); 912 __ j(above_equal, &miss);
806 // Check that the maps starting from the prototype haven't changed. 913 // Check that the maps starting from the prototype haven't changed.
807 GenerateDirectLoadGlobalFunctionPrototype( 914 GenerateDirectLoadGlobalFunctionPrototype(
808 masm(), Context::STRING_FUNCTION_INDEX, rax); 915 masm(), Context::STRING_FUNCTION_INDEX, rax);
809 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 916 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
810 rbx, rdx, name, &miss); 917 rbx, rdx, name, &miss, rdi);
811 } 918 }
812 break; 919 break;
813 920
814 case NUMBER_CHECK: { 921 case NUMBER_CHECK: {
815 if (!function->IsBuiltin()) { 922 if (!function->IsBuiltin()) {
816 // Calling non-builtins with a value as receiver requires boxing. 923 // Calling non-builtins with a value as receiver requires boxing.
817 __ jmp(&miss); 924 __ jmp(&miss);
818 } else { 925 } else {
819 Label fast; 926 Label fast;
820 // Check that the object is a smi or a heap number. 927 // Check that the object is a smi or a heap number.
821 __ JumpIfSmi(rdx, &fast); 928 __ JumpIfSmi(rdx, &fast);
822 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax); 929 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
823 __ j(not_equal, &miss); 930 __ j(not_equal, &miss);
824 __ bind(&fast); 931 __ bind(&fast);
825 // Check that the maps starting from the prototype haven't changed. 932 // Check that the maps starting from the prototype haven't changed.
826 GenerateDirectLoadGlobalFunctionPrototype( 933 GenerateDirectLoadGlobalFunctionPrototype(
827 masm(), Context::NUMBER_FUNCTION_INDEX, rax); 934 masm(), Context::NUMBER_FUNCTION_INDEX, rax);
828 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 935 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
829 rbx, rdx, name, &miss); 936 rbx, rdx, name, &miss, rdi);
830 } 937 }
831 break; 938 break;
832 } 939 }
833 940
834 case BOOLEAN_CHECK: { 941 case BOOLEAN_CHECK: {
835 if (!function->IsBuiltin()) { 942 if (!function->IsBuiltin()) {
836 // Calling non-builtins with a value as receiver requires boxing. 943 // Calling non-builtins with a value as receiver requires boxing.
837 __ jmp(&miss); 944 __ jmp(&miss);
838 } else { 945 } else {
839 Label fast; 946 Label fast;
840 // Check that the object is a boolean. 947 // Check that the object is a boolean.
841 __ CompareRoot(rdx, Heap::kTrueValueRootIndex); 948 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
842 __ j(equal, &fast); 949 __ j(equal, &fast);
843 __ CompareRoot(rdx, Heap::kFalseValueRootIndex); 950 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
844 __ j(not_equal, &miss); 951 __ j(not_equal, &miss);
845 __ bind(&fast); 952 __ bind(&fast);
846 // Check that the maps starting from the prototype haven't changed. 953 // Check that the maps starting from the prototype haven't changed.
847 GenerateDirectLoadGlobalFunctionPrototype( 954 GenerateDirectLoadGlobalFunctionPrototype(
848 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax); 955 masm(), Context::BOOLEAN_FUNCTION_INDEX, rax);
849 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 956 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
850 rbx, rdx, name, &miss); 957 rbx, rdx, name, &miss, rdi);
851 } 958 }
852 break; 959 break;
853 } 960 }
854 961
855 default: 962 default:
856 UNREACHABLE(); 963 UNREACHABLE();
857 } 964 }
858 965
859 if (depth != kInvalidProtoDepth) { 966 if (depth != kInvalidProtoDepth) {
860 GenerateFastApiCall(masm(), optimization, argc); 967 GenerateFastApiCall(masm(), optimization, argc);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
895 GenerateNameCheck(name, &miss); 1002 GenerateNameCheck(name, &miss);
896 1003
897 // Get the receiver from the stack. 1004 // Get the receiver from the stack.
898 const int argc = arguments().immediate(); 1005 const int argc = arguments().immediate();
899 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 1006 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
900 1007
901 // Check that the receiver isn't a smi. 1008 // Check that the receiver isn't a smi.
902 __ JumpIfSmi(rdx, &miss); 1009 __ JumpIfSmi(rdx, &miss);
903 1010
904 // Do the right check and compute the holder register. 1011 // Do the right check and compute the holder register.
905 Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, name, &miss); 1012 Register reg = CheckPrototypes(object, rdx, holder, rbx, rax,
1013 name, &miss, rdi);
906 1014
907 GenerateFastPropertyLoad(masm(), rdi, reg, holder, index); 1015 GenerateFastPropertyLoad(masm(), rdi, reg, holder, index);
908 1016
909 // Check that the function really is a function. 1017 // Check that the function really is a function.
910 __ JumpIfSmi(rdi, &miss); 1018 __ JumpIfSmi(rdi, &miss);
911 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx); 1019 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
912 __ j(not_equal, &miss); 1020 __ j(not_equal, &miss);
913 1021
914 // Patch the receiver on the stack with the global proxy if 1022 // Patch the receiver on the stack with the global proxy if
915 // necessary. 1023 // necessary.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 1067
960 // Check that the receiver isn't a smi. 1068 // Check that the receiver isn't a smi.
961 __ JumpIfSmi(rdx, &miss); 1069 __ JumpIfSmi(rdx, &miss);
962 1070
963 CheckPrototypes(JSObject::cast(object), 1071 CheckPrototypes(JSObject::cast(object),
964 rdx, 1072 rdx,
965 holder, 1073 holder,
966 rbx, 1074 rbx,
967 rax, 1075 rax,
968 name, 1076 name,
969 &miss); 1077 &miss,
1078 rdi);
970 1079
971 if (argc == 0) { 1080 if (argc == 0) {
972 // Noop, return the length. 1081 // Noop, return the length.
973 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset)); 1082 __ movq(rax, FieldOperand(rdx, JSArray::kLengthOffset));
974 __ ret((argc + 1) * kPointerSize); 1083 __ ret((argc + 1) * kPointerSize);
975 } else { 1084 } else {
976 // Get the elements array of the object. 1085 // Get the elements array of the object.
977 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); 1086 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
978 1087
979 // Check that the elements are in fast mode (not dictionary). 1088 // Check that the elements are in fast mode (not dictionary).
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 1221
1113 // Get the receiver from the stack. 1222 // Get the receiver from the stack.
1114 const int argc = arguments().immediate(); 1223 const int argc = arguments().immediate();
1115 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 1224 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1116 1225
1117 // Check that the receiver isn't a smi. 1226 // Check that the receiver isn't a smi.
1118 __ JumpIfSmi(rdx, &miss); 1227 __ JumpIfSmi(rdx, &miss);
1119 1228
1120 CheckPrototypes(JSObject::cast(object), rdx, 1229 CheckPrototypes(JSObject::cast(object), rdx,
1121 holder, rbx, 1230 holder, rbx,
1122 rax, name, &miss); 1231 rax, name, &miss, rdi);
1123 1232
1124 // Get the elements array of the object. 1233 // Get the elements array of the object.
1125 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset)); 1234 __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
1126 1235
1127 // Check that the elements are in fast mode (not dictionary). 1236 // Check that the elements are in fast mode (not dictionary).
1128 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), Factory::fixed_array_map()); 1237 __ Cmp(FieldOperand(rbx, HeapObject::kMapOffset), Factory::fixed_array_map());
1129 __ j(not_equal, &miss); 1238 __ j(not_equal, &miss);
1130 1239
1131 // Get the array's length into rcx and calculate new length. 1240 // Get the array's length into rcx and calculate new length.
1132 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset)); 1241 __ SmiToInteger32(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
1281 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 1390 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1282 1391
1283 // If the object is the holder then we know that it's a global 1392 // If the object is the holder then we know that it's a global
1284 // object which can only happen for contextual calls. In this case, 1393 // object which can only happen for contextual calls. In this case,
1285 // the receiver cannot be a smi. 1394 // the receiver cannot be a smi.
1286 if (object != holder) { 1395 if (object != holder) {
1287 __ JumpIfSmi(rdx, &miss); 1396 __ JumpIfSmi(rdx, &miss);
1288 } 1397 }
1289 1398
1290 // Check that the maps haven't changed. 1399 // Check that the maps haven't changed.
1291 CheckPrototypes(object, rdx, holder, rbx, rax, name, &miss); 1400 CheckPrototypes(object, rdx, holder, rbx, rax, name, &miss, rdi);
1292 1401
1293 // Get the value from the cell. 1402 // Get the value from the cell.
1294 __ Move(rdi, Handle<JSGlobalPropertyCell>(cell)); 1403 __ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
1295 __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset)); 1404 __ movq(rdi, FieldOperand(rdi, JSGlobalPropertyCell::kValueOffset));
1296 1405
1297 // Check that the cell contains the same function. 1406 // Check that the cell contains the same function.
1298 if (Heap::InNewSpace(function)) { 1407 if (Heap::InNewSpace(function)) {
1299 // We can't embed a pointer to a function in new space so we have 1408 // We can't embed a pointer to a function in new space so we have
1300 // to verify that the shared function info is unchanged. This has 1409 // to verify that the shared function info is unchanged. This has
1301 // the nice side effect that multiple closures based on the same 1410 // the nice side effect that multiple closures based on the same
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
1394 // -- rsp[0] : return address 1503 // -- rsp[0] : return address
1395 // ----------------------------------- 1504 // -----------------------------------
1396 Label miss; 1505 Label miss;
1397 1506
1398 // Chech that receiver is not a smi. 1507 // Chech that receiver is not a smi.
1399 __ JumpIfSmi(rax, &miss); 1508 __ JumpIfSmi(rax, &miss);
1400 1509
1401 // Check the maps of the full prototype chain. Also check that 1510 // Check the maps of the full prototype chain. Also check that
1402 // global property cells up to (but not including) the last object 1511 // global property cells up to (but not including) the last object
1403 // in the prototype chain are empty. 1512 // in the prototype chain are empty.
1404 CheckPrototypes(object, rax, last, rbx, rdx, name, &miss); 1513 CheckPrototypes(object, rax, last, rbx, rdx, name, &miss, rdi);
1405 1514
1406 // If the last object in the prototype chain is a global object, 1515 // If the last object in the prototype chain is a global object,
1407 // check that the global property cell is empty. 1516 // check that the global property cell is empty.
1408 if (last->IsGlobalObject()) { 1517 if (last->IsGlobalObject()) {
1409 Object* cell = GenerateCheckPropertyCell(masm(), 1518 Object* cell = GenerateCheckPropertyCell(masm(),
1410 GlobalObject::cast(last), 1519 GlobalObject::cast(last),
1411 name, 1520 name,
1412 rdx, 1521 rdx,
1413 &miss); 1522 &miss);
1414 if (cell->IsFailure()) return cell; 1523 if (cell->IsFailure()) return cell;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1493 Label miss; 1602 Label miss;
1494 1603
1495 // If the object is the holder then we know that it's a global 1604 // If the object is the holder then we know that it's a global
1496 // object which can only happen for contextual loads. In this case, 1605 // object which can only happen for contextual loads. In this case,
1497 // the receiver cannot be a smi. 1606 // the receiver cannot be a smi.
1498 if (object != holder) { 1607 if (object != holder) {
1499 __ JumpIfSmi(rax, &miss); 1608 __ JumpIfSmi(rax, &miss);
1500 } 1609 }
1501 1610
1502 // Check that the maps haven't changed. 1611 // Check that the maps haven't changed.
1503 CheckPrototypes(object, rax, holder, rbx, rdx, name, &miss); 1612 CheckPrototypes(object, rax, holder, rbx, rdx, name, &miss, rdi);
1504 1613
1505 // Get the value from the cell. 1614 // Get the value from the cell.
1506 __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); 1615 __ Move(rbx, Handle<JSGlobalPropertyCell>(cell));
1507 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); 1616 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset));
1508 1617
1509 // Check for deleted property if property can actually be deleted. 1618 // Check for deleted property if property can actually be deleted.
1510 if (!is_dont_delete) { 1619 if (!is_dont_delete) {
1511 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); 1620 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex);
1512 __ j(equal, &miss); 1621 __ j(equal, &miss);
1513 } else if (FLAG_debug_code) { 1622 } else if (FLAG_debug_code) {
(...skipping 606 matching lines...) Expand 10 before | Expand all | Expand 10 after
2120 2229
2121 Register StubCompiler::CheckPrototypes(JSObject* object, 2230 Register StubCompiler::CheckPrototypes(JSObject* object,
2122 Register object_reg, 2231 Register object_reg,
2123 JSObject* holder, 2232 JSObject* holder,
2124 Register holder_reg, 2233 Register holder_reg,
2125 Register scratch, 2234 Register scratch,
2126 String* name, 2235 String* name,
2127 int save_at_depth, 2236 int save_at_depth,
2128 Label* miss, 2237 Label* miss,
2129 Register extra) { 2238 Register extra) {
2130 // Check that the maps haven't changed. 2239 // Make sure there's no overlap between scratch and the other
2131 Register result = 2240 // registers.
2132 masm()->CheckMaps(object, 2241 ASSERT(!scratch.is(object_reg) && !scratch.is(holder_reg));
2133 object_reg, 2242
2134 holder, 2243 // Keep track of the current object in register reg. On the first
2135 holder_reg, 2244 // iteration, reg is an alias for object_reg, on later iterations,
2136 scratch, 2245 // it is an alias for holder_reg.
2137 save_at_depth, 2246 Register reg = object_reg;
2138 miss); 2247 int depth = 0;
2248
2249 if (save_at_depth == depth) {
2250 __ movq(Operand(rsp, kPointerSize), object_reg);
2251 }
2252
2253 // Check the maps in the prototype chain.
2254 // Traverse the prototype chain from the object and do map checks.
2255 JSObject* current = object;
2256 while (current != holder) {
2257 depth++;
2258
2259 // Only global objects and objects that do not require access
2260 // checks are allowed in stubs.
2261 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
2262
2263 JSObject* prototype = JSObject::cast(current->GetPrototype());
2264 if (!current->HasFastProperties() &&
2265 !current->IsJSGlobalObject() &&
2266 !current->IsJSGlobalProxy()) {
2267 if (!name->IsSymbol()) {
2268 Object* lookup_result = Heap::LookupSymbol(name);
2269 if (lookup_result->IsFailure()) {
2270 set_failure(Failure::cast(lookup_result));
2271 return reg;
2272 } else {
2273 name = String::cast(lookup_result);
2274 }
2275 }
2276 ASSERT(current->property_dictionary()->FindEntry(name) ==
2277 StringDictionary::kNotFound);
2278
2279 GenerateDictionaryNegativeLookup(masm(),
2280 miss,
2281 reg,
2282 name,
2283 scratch,
2284 extra);
2285 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2286 reg = holder_reg; // from now the object is in holder_reg
2287 __ movq(reg, FieldOperand(scratch, Map::kPrototypeOffset));
2288 } else if (Heap::InNewSpace(prototype)) {
2289 // Get the map of the current object.
2290 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2291 __ Cmp(scratch, Handle<Map>(current->map()));
2292 // Branch on the result of the map check.
2293 __ j(not_equal, miss);
2294 // Check access rights to the global object. This has to happen
2295 // after the map check so that we know that the object is
2296 // actually a global object.
2297 if (current->IsJSGlobalProxy()) {
2298 __ CheckAccessGlobalProxy(reg, scratch, miss);
2299
2300 // Restore scratch register to be the map of the object.
2301 // We load the prototype from the map in the scratch register.
2302 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
2303 }
2304 // The prototype is in new space; we cannot store a reference
2305 // to it in the code. Load it from the map.
2306 reg = holder_reg; // from now the object is in holder_reg
2307 __ movq(reg, FieldOperand(scratch, Map::kPrototypeOffset));
2308
2309 } else {
2310 // Check the map of the current object.
2311 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
2312 Handle<Map>(current->map()));
2313 // Branch on the result of the map check.
2314 __ j(not_equal, miss);
2315 // Check access rights to the global object. This has to happen
2316 // after the map check so that we know that the object is
2317 // actually a global object.
2318 if (current->IsJSGlobalProxy()) {
2319 __ CheckAccessGlobalProxy(reg, scratch, miss);
2320 }
2321 // The prototype is in old space; load it directly.
2322 reg = holder_reg; // from now the object is in holder_reg
2323 __ Move(reg, Handle<JSObject>(prototype));
2324 }
2325
2326 if (save_at_depth == depth) {
2327 __ movq(Operand(rsp, kPointerSize), reg);
2328 }
2329
2330 // Go to the next object in the prototype chain.
2331 current = prototype;
2332 }
2333
2334 // Check the holder map.
2335 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), Handle<Map>(holder->map()));
2336 __ j(not_equal, miss);
2337
2338 // Log the check depth.
2339 LOG(IntEvent("check-maps-depth", depth + 1));
2340
2341 // Perform security check for access to the global object and return
2342 // the holder register.
2343 ASSERT(current == holder);
2344 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
2345 if (current->IsJSGlobalProxy()) {
2346 __ CheckAccessGlobalProxy(reg, scratch, miss);
2347 }
2139 2348
2140 // If we've skipped any global objects, it's not enough to verify 2349 // If we've skipped any global objects, it's not enough to verify
2141 // that their maps haven't changed. We also need to check that the 2350 // that their maps haven't changed. We also need to check that the
2142 // property cell for the property is still empty. 2351 // property cell for the property is still empty.
2143 while (object != holder) { 2352 current = object;
2144 if (object->IsGlobalObject()) { 2353 while (current != holder) {
2354 if (current->IsGlobalObject()) {
2145 Object* cell = GenerateCheckPropertyCell(masm(), 2355 Object* cell = GenerateCheckPropertyCell(masm(),
2146 GlobalObject::cast(object), 2356 GlobalObject::cast(current),
2147 name, 2357 name,
2148 scratch, 2358 scratch,
2149 miss); 2359 miss);
2150 if (cell->IsFailure()) { 2360 if (cell->IsFailure()) {
2151 set_failure(Failure::cast(cell)); 2361 set_failure(Failure::cast(cell));
2152 return result; 2362 return reg;
2153 } 2363 }
2154 } 2364 }
2155 object = JSObject::cast(object->GetPrototype()); 2365 current = JSObject::cast(current->GetPrototype());
2156 } 2366 }
2157 2367
2158 // Return the register containing the holder. 2368 // Return the register containing the holder.
2159 return result; 2369 return reg;
2160 } 2370 }
2161 2371
2162 2372
2163 void StubCompiler::GenerateLoadField(JSObject* object, 2373 void StubCompiler::GenerateLoadField(JSObject* object,
2164 JSObject* holder, 2374 JSObject* holder,
2165 Register receiver, 2375 Register receiver,
2166 Register scratch1, 2376 Register scratch1,
2167 Register scratch2, 2377 Register scratch2,
2168 int index, 2378 int index,
2169 String* name, 2379 String* name,
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
2332 // Return the generated code. 2542 // Return the generated code.
2333 return GetCode(); 2543 return GetCode();
2334 } 2544 }
2335 2545
2336 2546
2337 #undef __ 2547 #undef __
2338 2548
2339 } } // namespace v8::internal 2549 } } // namespace v8::internal
2340 2550
2341 #endif // V8_TARGET_ARCH_X64 2551 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/macro-assembler-x64.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698