OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 1003 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1014 // If we've skipped any global objects, it's not enough to verify that | 1014 // If we've skipped any global objects, it's not enough to verify that |
1015 // their maps haven't changed. We also need to check that the property | 1015 // their maps haven't changed. We also need to check that the property |
1016 // cell for the property is still empty. | 1016 // cell for the property is still empty. |
1017 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); | 1017 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); |
1018 | 1018 |
1019 // Return the register containing the holder. | 1019 // Return the register containing the holder. |
1020 return reg; | 1020 return reg; |
1021 } | 1021 } |
1022 | 1022 |
1023 | 1023 |
1024 void StubCompiler::GenerateLoadField(Handle<JSObject> object, | 1024 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, |
1025 Handle<JSObject> holder, | 1025 Label* miss) { |
1026 Register receiver, | 1026 __ jmp(success); |
1027 Register scratch1, | 1027 __ bind(miss); |
1028 Register scratch2, | 1028 GenerateLoadMiss(masm(), kind()); |
1029 Register scratch3, | 1029 } |
1030 PropertyIndex index, | |
1031 Handle<String> name, | |
1032 Label* miss) { | |
1033 // Check that the receiver isn't a smi. | |
1034 __ JumpIfSmi(receiver, miss); | |
1035 | 1030 |
1036 // Check the prototype chain. | |
1037 Register reg = CheckPrototypes( | |
1038 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | |
1039 | 1031 |
| 1032 Register BaseLoadStubCompiler::CallbackHandlerFrontend( |
| 1033 Handle<JSObject> object, |
| 1034 Register object_reg, |
| 1035 Handle<JSObject> holder, |
| 1036 Handle<String> name, |
| 1037 Label* success, |
| 1038 FrontendCheckType check, |
| 1039 Handle<AccessorInfo> callback) { |
| 1040 Label miss; |
| 1041 |
| 1042 Register reg = HandlerFrontendHeader( |
| 1043 object, object_reg, holder, name, &miss, check); |
| 1044 |
| 1045 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 1046 ASSERT(!reg.is(scratch2())); |
| 1047 ASSERT(!reg.is(scratch3())); |
| 1048 ASSERT(!reg.is(scratch4())); |
| 1049 |
| 1050 // Load the properties dictionary. |
| 1051 Register dictionary = scratch4(); |
| 1052 __ movq(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); |
| 1053 |
| 1054 // Probe the dictionary. |
| 1055 Label probe_done; |
| 1056 StringDictionaryLookupStub::GeneratePositiveLookup(masm(), |
| 1057 &miss, |
| 1058 &probe_done, |
| 1059 dictionary, |
| 1060 this->name(), |
| 1061 scratch2(), |
| 1062 scratch3()); |
| 1063 __ bind(&probe_done); |
| 1064 |
| 1065 // If probing finds an entry in the dictionary, scratch3 contains the |
| 1066 // index into the dictionary. Check that the value is the callback. |
| 1067 Register index = scratch3(); |
| 1068 const int kElementsStartOffset = |
| 1069 StringDictionary::kHeaderSize + |
| 1070 StringDictionary::kElementsStartIndex * kPointerSize; |
| 1071 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 1072 __ movq(scratch2(), |
| 1073 Operand(dictionary, index, times_pointer_size, |
| 1074 kValueOffset - kHeapObjectTag)); |
| 1075 __ movq(scratch3(), callback, RelocInfo::EMBEDDED_OBJECT); |
| 1076 __ cmpq(scratch2(), scratch3()); |
| 1077 __ j(not_equal, &miss); |
| 1078 } |
| 1079 |
| 1080 HandlerFrontendFooter(success, &miss); |
| 1081 return reg; |
| 1082 } |
| 1083 |
| 1084 |
| 1085 void BaseLoadStubCompiler::NonexistentHandlerFrontend( |
| 1086 Handle<JSObject> object, |
| 1087 Handle<JSObject> last, |
| 1088 Handle<String> name, |
| 1089 Label* success, |
| 1090 Handle<GlobalObject> global) { |
| 1091 Label miss; |
| 1092 |
| 1093 Register reg = HandlerFrontendHeader( |
| 1094 object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS); |
| 1095 |
| 1096 // If the last object in the prototype chain is a global object, |
| 1097 // check that the global property cell is empty. |
| 1098 if (!global.is_null()) { |
| 1099 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); |
| 1100 } |
| 1101 |
| 1102 if (!last->HasFastProperties()) { |
| 1103 __ movq(scratch2(), FieldOperand(reg, HeapObject::kMapOffset)); |
| 1104 __ movq(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset)); |
| 1105 __ Cmp(scratch2(), isolate()->factory()->null_value()); |
| 1106 __ j(not_equal, &miss); |
| 1107 } |
| 1108 |
| 1109 HandlerFrontendFooter(success, &miss); |
| 1110 } |
| 1111 |
| 1112 |
| 1113 void BaseLoadStubCompiler::GenerateLoadField(Register reg, |
| 1114 Handle<JSObject> holder, |
| 1115 PropertyIndex index) { |
1040 // Get the value from the properties. | 1116 // Get the value from the properties. |
1041 GenerateFastPropertyLoad(masm(), rax, reg, holder, index); | 1117 GenerateFastPropertyLoad(masm(), rax, reg, holder, index); |
1042 __ ret(0); | 1118 __ ret(0); |
1043 } | 1119 } |
1044 | 1120 |
1045 | 1121 |
1046 void StubCompiler::GenerateDictionaryLoadCallback(Register receiver, | 1122 void BaseLoadStubCompiler::GenerateLoadCallback(Register reg, |
1047 Register name_reg, | 1123 Handle<AccessorInfo> callback) { |
1048 Register scratch1, | 1124 // Insert additional parameters into the stack frame above return address. |
1049 Register scratch2, | 1125 ASSERT(!scratch2().is(reg)); |
1050 Register scratch3, | 1126 __ pop(scratch2()); // Get return address to place it below. |
1051 Handle<AccessorInfo> callback, | |
1052 Handle<String> name, | |
1053 Label* miss) { | |
1054 ASSERT(!receiver.is(scratch1)); | |
1055 ASSERT(!receiver.is(scratch2)); | |
1056 ASSERT(!receiver.is(scratch3)); | |
1057 | 1127 |
1058 // Load the properties dictionary. | 1128 __ push(receiver()); // receiver |
1059 Register dictionary = scratch1; | |
1060 __ movq(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset)); | |
1061 | |
1062 // Probe the dictionary. | |
1063 Label probe_done; | |
1064 StringDictionaryLookupStub::GeneratePositiveLookup(masm(), | |
1065 miss, | |
1066 &probe_done, | |
1067 dictionary, | |
1068 name_reg, | |
1069 scratch2, | |
1070 scratch3); | |
1071 __ bind(&probe_done); | |
1072 | |
1073 // If probing finds an entry in the dictionary, scratch3 contains the | |
1074 // index into the dictionary. Check that the value is the callback. | |
1075 Register index = scratch3; | |
1076 const int kElementsStartOffset = | |
1077 StringDictionary::kHeaderSize + | |
1078 StringDictionary::kElementsStartIndex * kPointerSize; | |
1079 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
1080 __ movq(scratch2, | |
1081 Operand(dictionary, index, times_pointer_size, | |
1082 kValueOffset - kHeapObjectTag)); | |
1083 __ movq(scratch3, callback, RelocInfo::EMBEDDED_OBJECT); | |
1084 __ cmpq(scratch2, scratch3); | |
1085 __ j(not_equal, miss); | |
1086 } | |
1087 | |
1088 | |
1089 void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, | |
1090 Handle<JSObject> holder, | |
1091 Register receiver, | |
1092 Register name_reg, | |
1093 Register scratch1, | |
1094 Register scratch2, | |
1095 Register scratch3, | |
1096 Register scratch4, | |
1097 Handle<AccessorInfo> callback, | |
1098 Handle<String> name, | |
1099 Label* miss) { | |
1100 // Check that the receiver isn't a smi. | |
1101 __ JumpIfSmi(receiver, miss); | |
1102 | |
1103 // Check that the maps haven't changed. | |
1104 Register reg = CheckPrototypes(object, receiver, holder, scratch1, | |
1105 scratch2, scratch3, name, miss); | |
1106 | |
1107 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | |
1108 GenerateDictionaryLoadCallback( | |
1109 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss); | |
1110 } | |
1111 | |
1112 // Insert additional parameters into the stack frame above return address. | |
1113 ASSERT(!scratch2.is(reg)); | |
1114 __ pop(scratch2); // Get return address to place it below. | |
1115 | |
1116 __ push(receiver); // receiver | |
1117 __ push(reg); // holder | 1129 __ push(reg); // holder |
1118 if (heap()->InNewSpace(callback->data())) { | 1130 if (heap()->InNewSpace(callback->data())) { |
1119 __ Move(scratch1, callback); | 1131 __ Move(scratch1(), callback); |
1120 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); // data | 1132 __ push(FieldOperand(scratch1(), AccessorInfo::kDataOffset)); // data |
1121 } else { | 1133 } else { |
1122 __ Push(Handle<Object>(callback->data())); | 1134 __ Push(Handle<Object>(callback->data())); |
1123 } | 1135 } |
1124 __ PushAddress(ExternalReference::isolate_address()); // isolate | 1136 __ PushAddress(ExternalReference::isolate_address()); // isolate |
1125 __ push(name_reg); // name | 1137 __ push(name()); // name |
1126 // Save a pointer to where we pushed the arguments pointer. | 1138 // Save a pointer to where we pushed the arguments pointer. |
1127 // This will be passed as the const AccessorInfo& to the C++ callback. | 1139 // This will be passed as the const AccessorInfo& to the C++ callback. |
1128 | 1140 |
1129 #if defined(__MINGW64__) | 1141 #if defined(__MINGW64__) |
1130 Register accessor_info_arg = rdx; | 1142 Register accessor_info_arg = rdx; |
1131 Register name_arg = rcx; | 1143 Register name_arg = rcx; |
1132 #elif defined(_WIN64) | 1144 #elif defined(_WIN64) |
1133 // Win64 uses first register--rcx--for returned value. | 1145 // Win64 uses first register--rcx--for returned value. |
1134 Register accessor_info_arg = r8; | 1146 Register accessor_info_arg = r8; |
1135 Register name_arg = rdx; | 1147 Register name_arg = rdx; |
1136 #else | 1148 #else |
1137 Register accessor_info_arg = rsi; | 1149 Register accessor_info_arg = rsi; |
1138 Register name_arg = rdi; | 1150 Register name_arg = rdi; |
1139 #endif | 1151 #endif |
1140 | 1152 |
1141 ASSERT(!name_arg.is(scratch2)); | 1153 ASSERT(!name_arg.is(scratch2())); |
1142 __ movq(name_arg, rsp); | 1154 __ movq(name_arg, rsp); |
1143 __ push(scratch2); // Restore return address. | 1155 __ push(scratch2()); // Restore return address. |
1144 | 1156 |
1145 // 4 elements array for v8::Arguments::values_ and handler for name. | 1157 // 4 elements array for v8::Arguments::values_ and handler for name. |
1146 const int kStackSpace = 5; | 1158 const int kStackSpace = 5; |
1147 | 1159 |
1148 // Allocate v8::AccessorInfo in non-GCed stack space. | 1160 // Allocate v8::AccessorInfo in non-GCed stack space. |
1149 const int kArgStackSpace = 1; | 1161 const int kArgStackSpace = 1; |
1150 | 1162 |
1151 __ PrepareCallApiFunction(kArgStackSpace); | 1163 __ PrepareCallApiFunction(kArgStackSpace); |
1152 __ lea(rax, Operand(name_arg, 4 * kPointerSize)); | 1164 __ lea(rax, Operand(name_arg, 4 * kPointerSize)); |
1153 | 1165 |
1154 // v8::AccessorInfo::args_. | 1166 // v8::AccessorInfo::args_. |
1155 __ movq(StackSpaceOperand(0), rax); | 1167 __ movq(StackSpaceOperand(0), rax); |
1156 | 1168 |
1157 // The context register (rsi) has been saved in PrepareCallApiFunction and | 1169 // The context register (rsi) has been saved in PrepareCallApiFunction and |
1158 // could be used to pass arguments. | 1170 // could be used to pass arguments. |
1159 __ lea(accessor_info_arg, StackSpaceOperand(0)); | 1171 __ lea(accessor_info_arg, StackSpaceOperand(0)); |
1160 | 1172 |
1161 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1173 Address getter_address = v8::ToCData<Address>(callback->getter()); |
1162 __ CallApiFunctionAndReturn(getter_address, kStackSpace); | 1174 __ CallApiFunctionAndReturn(getter_address, kStackSpace); |
1163 } | 1175 } |
1164 | 1176 |
1165 | 1177 |
1166 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, | 1178 void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) { |
1167 Handle<JSObject> holder, | |
1168 Register receiver, | |
1169 Register scratch1, | |
1170 Register scratch2, | |
1171 Register scratch3, | |
1172 Handle<JSFunction> value, | |
1173 Handle<String> name, | |
1174 Label* miss) { | |
1175 // Check that the receiver isn't a smi. | |
1176 __ JumpIfSmi(receiver, miss); | |
1177 | |
1178 // Check that the maps haven't changed. | |
1179 CheckPrototypes( | |
1180 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | |
1181 | |
1182 // Return the constant value. | 1179 // Return the constant value. |
1183 __ LoadHeapObject(rax, value); | 1180 __ LoadHeapObject(rax, value); |
1184 __ ret(0); | 1181 __ ret(0); |
1185 } | 1182 } |
1186 | 1183 |
1187 | 1184 |
1188 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, | 1185 void BaseLoadStubCompiler::GenerateLoadInterceptor( |
1189 Handle<JSObject> interceptor_holder, | 1186 Register holder_reg, |
1190 LookupResult* lookup, | 1187 Handle<JSObject> object, |
1191 Register receiver, | 1188 Handle<JSObject> interceptor_holder, |
1192 Register name_reg, | 1189 LookupResult* lookup, |
1193 Register scratch1, | 1190 Handle<String> name) { |
1194 Register scratch2, | |
1195 Register scratch3, | |
1196 Handle<String> name, | |
1197 Label* miss) { | |
1198 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1191 ASSERT(interceptor_holder->HasNamedInterceptor()); |
1199 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 1192 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
1200 | 1193 |
1201 // Check that the receiver isn't a smi. | |
1202 __ JumpIfSmi(receiver, miss); | |
1203 | |
1204 // So far the most popular follow ups for interceptor loads are FIELD | 1194 // So far the most popular follow ups for interceptor loads are FIELD |
1205 // and CALLBACKS, so inline only them, other cases may be added | 1195 // and CALLBACKS, so inline only them, other cases may be added |
1206 // later. | 1196 // later. |
1207 bool compile_followup_inline = false; | 1197 bool compile_followup_inline = false; |
1208 if (lookup->IsFound() && lookup->IsCacheable()) { | 1198 if (lookup->IsFound() && lookup->IsCacheable()) { |
1209 if (lookup->IsField()) { | 1199 if (lookup->IsField()) { |
1210 compile_followup_inline = true; | 1200 compile_followup_inline = true; |
1211 } else if (lookup->type() == CALLBACKS && | 1201 } else if (lookup->type() == CALLBACKS && |
1212 lookup->GetCallbackObject()->IsAccessorInfo()) { | 1202 lookup->GetCallbackObject()->IsAccessorInfo()) { |
1213 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1203 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
1214 compile_followup_inline = callback->getter() != NULL && | 1204 compile_followup_inline = callback->getter() != NULL && |
1215 callback->IsCompatibleReceiver(*object); | 1205 callback->IsCompatibleReceiver(*object); |
1216 } | 1206 } |
1217 } | 1207 } |
1218 | 1208 |
1219 if (compile_followup_inline) { | 1209 if (compile_followup_inline) { |
1220 // Compile the interceptor call, followed by inline code to load the | 1210 // Compile the interceptor call, followed by inline code to load the |
1221 // property from further up the prototype chain if the call fails. | 1211 // property from further up the prototype chain if the call fails. |
1222 // Check that the maps haven't changed. | 1212 // Check that the maps haven't changed. |
1223 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1213 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
1224 scratch1, scratch2, scratch3, | |
1225 name, miss); | |
1226 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); | |
1227 | 1214 |
1228 // Preserve the receiver register explicitly whenever it is different from | 1215 // Preserve the receiver register explicitly whenever it is different from |
1229 // the holder and it is needed should the interceptor return without any | 1216 // the holder and it is needed should the interceptor return without any |
1230 // result. The CALLBACKS case needs the receiver to be passed into C++ code, | 1217 // result. The CALLBACKS case needs the receiver to be passed into C++ code, |
1231 // the FIELD case might cause a miss during the prototype check. | 1218 // the FIELD case might cause a miss during the prototype check. |
1232 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); | 1219 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); |
1233 bool must_preserve_receiver_reg = !receiver.is(holder_reg) && | 1220 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
1234 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); | 1221 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
1235 | 1222 |
1236 // Save necessary data before invoking an interceptor. | 1223 // Save necessary data before invoking an interceptor. |
1237 // Requires a frame to make GC aware of pushed pointers. | 1224 // Requires a frame to make GC aware of pushed pointers. |
1238 { | 1225 { |
1239 FrameScope frame_scope(masm(), StackFrame::INTERNAL); | 1226 FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
1240 | 1227 |
1241 if (must_preserve_receiver_reg) { | 1228 if (must_preserve_receiver_reg) { |
1242 __ push(receiver); | 1229 __ push(receiver()); |
1243 } | 1230 } |
1244 __ push(holder_reg); | 1231 __ push(holder_reg); |
1245 __ push(name_reg); | 1232 __ push(this->name()); |
1246 | 1233 |
1247 // Invoke an interceptor. Note: map checks from receiver to | 1234 // Invoke an interceptor. Note: map checks from receiver to |
1248 // interceptor's holder has been compiled before (see a caller | 1235 // interceptor's holder has been compiled before (see a caller |
1249 // of this method.) | 1236 // of this method.) |
1250 CompileCallLoadPropertyWithInterceptor(masm(), | 1237 CompileCallLoadPropertyWithInterceptor(masm(), |
1251 receiver, | 1238 receiver(), |
1252 holder_reg, | 1239 holder_reg, |
1253 name_reg, | 1240 this->name(), |
1254 interceptor_holder); | 1241 interceptor_holder); |
1255 | 1242 |
1256 // Check if interceptor provided a value for property. If it's | 1243 // Check if interceptor provided a value for property. If it's |
1257 // the case, return immediately. | 1244 // the case, return immediately. |
1258 Label interceptor_failed; | 1245 Label interceptor_failed; |
1259 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); | 1246 __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
1260 __ j(equal, &interceptor_failed); | 1247 __ j(equal, &interceptor_failed); |
1261 frame_scope.GenerateLeaveFrame(); | 1248 frame_scope.GenerateLeaveFrame(); |
1262 __ ret(0); | 1249 __ ret(0); |
1263 | 1250 |
1264 __ bind(&interceptor_failed); | 1251 __ bind(&interceptor_failed); |
1265 __ pop(name_reg); | 1252 __ pop(this->name()); |
1266 __ pop(holder_reg); | 1253 __ pop(holder_reg); |
1267 if (must_preserve_receiver_reg) { | 1254 if (must_preserve_receiver_reg) { |
1268 __ pop(receiver); | 1255 __ pop(receiver()); |
1269 } | 1256 } |
1270 | 1257 |
1271 // Leave the internal frame. | 1258 // Leave the internal frame. |
1272 } | 1259 } |
1273 | 1260 |
1274 // Check that the maps from interceptor's holder to lookup's holder | 1261 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup); |
1275 // haven't changed. And load lookup's holder into |holder| register. | |
1276 if (must_perfrom_prototype_check) { | |
1277 holder_reg = CheckPrototypes(interceptor_holder, | |
1278 holder_reg, | |
1279 Handle<JSObject>(lookup->holder()), | |
1280 scratch1, | |
1281 scratch2, | |
1282 scratch3, | |
1283 name, | |
1284 miss); | |
1285 } | |
1286 | |
1287 if (lookup->IsField()) { | |
1288 // We found FIELD property in prototype chain of interceptor's holder. | |
1289 // Retrieve a field from field's holder. | |
1290 GenerateFastPropertyLoad(masm(), rax, holder_reg, | |
1291 Handle<JSObject>(lookup->holder()), | |
1292 lookup->GetFieldIndex()); | |
1293 __ ret(0); | |
1294 } else { | |
1295 // We found CALLBACKS property in prototype chain of interceptor's | |
1296 // holder. | |
1297 ASSERT(lookup->type() == CALLBACKS); | |
1298 Handle<AccessorInfo> callback( | |
1299 AccessorInfo::cast(lookup->GetCallbackObject())); | |
1300 ASSERT(callback->getter() != NULL); | |
1301 | |
1302 // Tail call to runtime. | |
1303 // Important invariant in CALLBACKS case: the code above must be | |
1304 // structured to never clobber |receiver| register. | |
1305 __ pop(scratch2); // return address | |
1306 __ push(receiver); | |
1307 __ push(holder_reg); | |
1308 __ Move(holder_reg, callback); | |
1309 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); | |
1310 __ PushAddress(ExternalReference::isolate_address()); | |
1311 __ push(holder_reg); | |
1312 __ push(name_reg); | |
1313 __ push(scratch2); // restore return address | |
1314 | |
1315 ExternalReference ref = | |
1316 ExternalReference(IC_Utility(IC::kLoadCallbackProperty), | |
1317 isolate()); | |
1318 __ TailCallExternalReference(ref, 6, 1); | |
1319 } | |
1320 } else { // !compile_followup_inline | 1262 } else { // !compile_followup_inline |
1321 // Call the runtime system to load the interceptor. | 1263 // Call the runtime system to load the interceptor. |
1322 // Check that the maps haven't changed. | 1264 // Check that the maps haven't changed. |
1323 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1265 __ pop(scratch2()); // save old return address |
1324 scratch1, scratch2, scratch3, | 1266 PushInterceptorArguments(masm(), receiver(), holder_reg, |
1325 name, miss); | 1267 this->name(), interceptor_holder); |
1326 __ pop(scratch2); // save old return address | 1268 __ push(scratch2()); // restore old return address |
1327 PushInterceptorArguments(masm(), receiver, holder_reg, | |
1328 name_reg, interceptor_holder); | |
1329 __ push(scratch2); // restore old return address | |
1330 | 1269 |
1331 ExternalReference ref = ExternalReference( | 1270 ExternalReference ref = ExternalReference( |
1332 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); | 1271 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), isolate()); |
1333 __ TailCallExternalReference(ref, 6, 1); | 1272 __ TailCallExternalReference(ref, 6, 1); |
1334 } | 1273 } |
1335 } | 1274 } |
1336 | 1275 |
1337 | 1276 |
1338 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { | 1277 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { |
1339 if (kind_ == Code::KEYED_CALL_IC) { | 1278 if (kind_ == Code::KEYED_CALL_IC) { |
(...skipping 1448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2788 // Return the generated code. | 2727 // Return the generated code. |
2789 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC); | 2728 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC); |
2790 } | 2729 } |
2791 | 2730 |
2792 | 2731 |
2793 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( | 2732 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( |
2794 Handle<JSObject> object, | 2733 Handle<JSObject> object, |
2795 Handle<JSObject> last, | 2734 Handle<JSObject> last, |
2796 Handle<String> name, | 2735 Handle<String> name, |
2797 Handle<GlobalObject> global) { | 2736 Handle<GlobalObject> global) { |
2798 // ----------- S t a t e ------------- | 2737 Label success; |
2799 // -- rax : receiver | |
2800 // -- rcx : name | |
2801 // -- rsp[0] : return address | |
2802 // ----------------------------------- | |
2803 Label miss; | |
2804 | 2738 |
2805 // Check that receiver is not a smi. | 2739 NonexistentHandlerFrontend(object, last, name, &success, global); |
2806 __ JumpIfSmi(rax, &miss); | |
2807 | 2740 |
2808 // Check the maps of the full prototype chain. Also check that | 2741 __ bind(&success); |
2809 // global property cells up to (but not including) the last object | |
2810 // in the prototype chain are empty. | |
2811 Register scratch = rdx; | |
2812 Register result = | |
2813 CheckPrototypes(object, rax, last, rbx, scratch, rdi, name, &miss); | |
2814 | |
2815 // If the last object in the prototype chain is a global object, | |
2816 // check that the global property cell is empty. | |
2817 if (!global.is_null()) { | |
2818 GenerateCheckPropertyCell(masm(), global, name, scratch, &miss); | |
2819 } | |
2820 | |
2821 if (!last->HasFastProperties()) { | |
2822 __ movq(scratch, FieldOperand(result, HeapObject::kMapOffset)); | |
2823 __ movq(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); | |
2824 __ Cmp(scratch, isolate()->factory()->null_value()); | |
2825 __ j(not_equal, &miss); | |
2826 } | |
2827 | |
2828 // Return undefined if maps of the full prototype chain are still the | 2742 // Return undefined if maps of the full prototype chain are still the |
2829 // same and no global property with this name contains a value. | 2743 // same and no global property with this name contains a value. |
2830 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 2744 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
2831 __ ret(0); | 2745 __ ret(0); |
2832 | 2746 |
2833 __ bind(&miss); | |
2834 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
2835 | |
2836 // Return the generated code. | 2747 // Return the generated code. |
2837 return GetCode(Code::NONEXISTENT, factory()->empty_string()); | 2748 return GetCode(Code::NONEXISTENT, factory()->empty_string()); |
2838 } | 2749 } |
2839 | 2750 |
2840 | 2751 |
2841 Register* LoadStubCompiler::registers() { | 2752 Register* LoadStubCompiler::registers() { |
2842 // receiver, name, scratch1, scratch2, scratch3, scratch4. | 2753 // receiver, name, scratch1, scratch2, scratch3, scratch4. |
2843 static Register registers[] = { rax, rcx, rdx, rbx, rdi, r8 }; | 2754 static Register registers[] = { rax, rcx, rdx, rbx, rdi, r8 }; |
2844 return registers; | 2755 return registers; |
2845 } | 2756 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2890 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2801 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
2891 } | 2802 } |
2892 __ ret(0); | 2803 __ ret(0); |
2893 } | 2804 } |
2894 | 2805 |
2895 | 2806 |
2896 #undef __ | 2807 #undef __ |
2897 #define __ ACCESS_MASM(masm()) | 2808 #define __ ACCESS_MASM(masm()) |
2898 | 2809 |
2899 | 2810 |
2900 Handle<Code> LoadStubCompiler::CompileLoadViaGetter( | |
2901 Handle<JSObject> receiver, | |
2902 Handle<JSObject> holder, | |
2903 Handle<String> name, | |
2904 Handle<JSFunction> getter) { | |
2905 // ----------- S t a t e ------------- | |
2906 // -- rax : receiver | |
2907 // -- rcx : name | |
2908 // -- rsp[0] : return address | |
2909 // ----------------------------------- | |
2910 Label miss; | |
2911 | |
2912 // Check that the maps haven't changed. | |
2913 __ JumpIfSmi(rax, &miss); | |
2914 CheckPrototypes(receiver, rax, holder, rbx, rdx, rdi, name, &miss); | |
2915 | |
2916 GenerateLoadViaGetter(masm(), getter), | |
2917 | |
2918 __ bind(&miss); | |
2919 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
2920 | |
2921 // Return the generated code. | |
2922 return GetCode(Code::CALLBACKS, name); | |
2923 } | |
2924 | |
2925 | |
2926 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2811 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
2927 Handle<JSObject> object, | 2812 Handle<JSObject> object, |
2928 Handle<GlobalObject> holder, | 2813 Handle<GlobalObject> global, |
2929 Handle<JSGlobalPropertyCell> cell, | 2814 Handle<JSGlobalPropertyCell> cell, |
2930 Handle<String> name, | 2815 Handle<String> name, |
2931 bool is_dont_delete) { | 2816 bool is_dont_delete) { |
2932 // ----------- S t a t e ------------- | 2817 Label success, miss; |
2933 // -- rax : receiver | 2818 // TODO(verwaest): Directly store to rax. Currently we cannot do this, since |
2934 // -- rcx : name | 2819 // rax is used as receiver(), which we would otherwise clobber before a |
2935 // -- rsp[0] : return address | 2820 // potential miss. |
2936 // ----------------------------------- | |
2937 Label miss; | |
2938 | 2821 |
2939 // Check that the maps haven't changed. | 2822 HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global), |
2940 __ JumpIfSmi(rax, &miss); | 2823 name, &miss, PERFORM_INITIAL_CHECKS); |
2941 CheckPrototypes(object, rax, holder, rbx, rdx, rdi, name, &miss); | |
2942 | 2824 |
2943 // Get the value from the cell. | 2825 // Get the value from the cell. |
2944 __ Move(rbx, cell); | 2826 __ Move(rbx, cell); |
2945 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); | 2827 __ movq(rbx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); |
2946 | 2828 |
2947 // Check for deleted property if property can actually be deleted. | 2829 // Check for deleted property if property can actually be deleted. |
2948 if (!is_dont_delete) { | 2830 if (!is_dont_delete) { |
2949 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 2831 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); |
2950 __ j(equal, &miss); | 2832 __ j(equal, &miss); |
2951 } else if (FLAG_debug_code) { | 2833 } else if (FLAG_debug_code) { |
2952 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); | 2834 __ CompareRoot(rbx, Heap::kTheHoleValueRootIndex); |
2953 __ Check(not_equal, "DontDelete cells can't contain the hole"); | 2835 __ Check(not_equal, "DontDelete cells can't contain the hole"); |
2954 } | 2836 } |
2955 | 2837 |
| 2838 HandlerFrontendFooter(&success, &miss); |
| 2839 __ bind(&success); |
| 2840 |
2956 Counters* counters = isolate()->counters(); | 2841 Counters* counters = isolate()->counters(); |
2957 __ IncrementCounter(counters->named_load_global_stub(), 1); | 2842 __ IncrementCounter(counters->named_load_global_stub(), 1); |
2958 __ movq(rax, rbx); | 2843 __ movq(rax, rbx); |
2959 __ ret(0); | 2844 __ ret(0); |
2960 | 2845 |
2961 __ bind(&miss); | |
2962 __ IncrementCounter(counters->named_load_global_stub_miss(), 1); | |
2963 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
2964 | |
2965 // Return the generated code. | 2846 // Return the generated code. |
2966 return GetCode(Code::NORMAL, name); | 2847 return GetCode(Code::NORMAL, name); |
2967 } | 2848 } |
2968 | 2849 |
2969 | 2850 |
2970 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( | 2851 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( |
2971 Handle<Map> receiver_map) { | 2852 Handle<Map> receiver_map) { |
2972 // ----------- S t a t e ------------- | 2853 // ----------- S t a t e ------------- |
2973 // -- rax : key | 2854 // -- rax : key |
2974 // -- rdx : receiver | 2855 // -- rdx : receiver |
(...skipping 718 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3693 __ jmp(ic_slow, RelocInfo::CODE_TARGET); | 3574 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
3694 } | 3575 } |
3695 } | 3576 } |
3696 | 3577 |
3697 | 3578 |
3698 #undef __ | 3579 #undef __ |
3699 | 3580 |
3700 } } // namespace v8::internal | 3581 } } // namespace v8::internal |
3701 | 3582 |
3702 #endif // V8_TARGET_ARCH_X64 | 3583 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |