| 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 |