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 1026 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1037 // If we've skipped any global objects, it's not enough to verify that | 1037 // If we've skipped any global objects, it's not enough to verify that |
1038 // their maps haven't changed. We also need to check that the property | 1038 // their maps haven't changed. We also need to check that the property |
1039 // cell for the property is still empty. | 1039 // cell for the property is still empty. |
1040 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); | 1040 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); |
1041 | 1041 |
1042 // Return the register containing the holder. | 1042 // Return the register containing the holder. |
1043 return reg; | 1043 return reg; |
1044 } | 1044 } |
1045 | 1045 |
1046 | 1046 |
1047 void StubCompiler::GenerateLoadField(Handle<JSObject> object, | 1047 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, |
1048 Handle<JSObject> holder, | 1048 Label* miss) { |
1049 Register receiver, | 1049 __ jmp(success); |
1050 Register scratch1, | 1050 __ bind(miss); |
1051 Register scratch2, | 1051 GenerateLoadMiss(masm(), kind()); |
1052 Register scratch3, | 1052 } |
1053 PropertyIndex index, | |
1054 Handle<String> name, | |
1055 Label* miss) { | |
1056 // Check that the receiver isn't a smi. | |
1057 __ JumpIfSmi(receiver, miss); | |
1058 | 1053 |
1059 // Check the prototype chain. | |
1060 Register reg = CheckPrototypes( | |
1061 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | |
1062 | 1054 |
| 1055 Register BaseLoadStubCompiler::CallbackHandlerFrontend( |
| 1056 Handle<JSObject> object, |
| 1057 Register object_reg, |
| 1058 Handle<JSObject> holder, |
| 1059 Handle<String> name, |
| 1060 Label* success, |
| 1061 FrontendCheckType check, |
| 1062 Handle<AccessorInfo> callback) { |
| 1063 Label miss; |
| 1064 |
| 1065 Register reg = HandlerFrontendHeader( |
| 1066 object, object_reg, holder, name, &miss, check); |
| 1067 |
| 1068 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 1069 ASSERT(!reg.is(scratch2())); |
| 1070 ASSERT(!reg.is(scratch3())); |
| 1071 Register dictionary = scratch1(); |
| 1072 bool must_preserve_dictionary_reg = reg.is(dictionary); |
| 1073 |
| 1074 // Load the properties dictionary. |
| 1075 if (must_preserve_dictionary_reg) { |
| 1076 __ push(dictionary); |
| 1077 } |
| 1078 __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); |
| 1079 |
| 1080 // Probe the dictionary. |
| 1081 Label probe_done, pop_and_miss; |
| 1082 StringDictionaryLookupStub::GeneratePositiveLookup(masm(), |
| 1083 &pop_and_miss, |
| 1084 &probe_done, |
| 1085 dictionary, |
| 1086 this->name(), |
| 1087 scratch2(), |
| 1088 scratch3()); |
| 1089 __ bind(&pop_and_miss); |
| 1090 if (must_preserve_dictionary_reg) { |
| 1091 __ pop(dictionary); |
| 1092 } |
| 1093 __ jmp(&miss); |
| 1094 __ bind(&probe_done); |
| 1095 |
| 1096 // If probing finds an entry in the dictionary, scratch2 contains the |
| 1097 // index into the dictionary. Check that the value is the callback. |
| 1098 Register index = scratch2(); |
| 1099 const int kElementsStartOffset = |
| 1100 StringDictionary::kHeaderSize + |
| 1101 StringDictionary::kElementsStartIndex * kPointerSize; |
| 1102 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 1103 __ mov(scratch3(), |
| 1104 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag)); |
| 1105 if (must_preserve_dictionary_reg) { |
| 1106 __ pop(dictionary); |
| 1107 } |
| 1108 __ cmp(scratch3(), callback); |
| 1109 __ j(not_equal, &miss); |
| 1110 } |
| 1111 |
| 1112 HandlerFrontendFooter(success, &miss); |
| 1113 return reg; |
| 1114 } |
| 1115 |
| 1116 |
| 1117 void BaseLoadStubCompiler::NonexistentHandlerFrontend( |
| 1118 Handle<JSObject> object, |
| 1119 Handle<JSObject> last, |
| 1120 Handle<String> name, |
| 1121 Label* success, |
| 1122 Handle<GlobalObject> global) { |
| 1123 Label miss; |
| 1124 |
| 1125 Register reg = HandlerFrontendHeader( |
| 1126 object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS); |
| 1127 |
| 1128 // If the last object in the prototype chain is a global object, |
| 1129 // check that the global property cell is empty. |
| 1130 if (!global.is_null()) { |
| 1131 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); |
| 1132 } |
| 1133 |
| 1134 if (!last->HasFastProperties()) { |
| 1135 __ mov(scratch2(), FieldOperand(reg, HeapObject::kMapOffset)); |
| 1136 __ mov(scratch2(), FieldOperand(scratch2(), Map::kPrototypeOffset)); |
| 1137 __ cmp(scratch2(), isolate()->factory()->null_value()); |
| 1138 __ j(not_equal, &miss); |
| 1139 } |
| 1140 |
| 1141 HandlerFrontendFooter(success, &miss); |
| 1142 } |
| 1143 |
| 1144 |
| 1145 void BaseLoadStubCompiler::GenerateLoadField(Register reg, |
| 1146 Handle<JSObject> holder, |
| 1147 PropertyIndex index) { |
1063 // Get the value from the properties. | 1148 // Get the value from the properties. |
1064 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); | 1149 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
1065 __ ret(0); | 1150 __ ret(0); |
1066 } | 1151 } |
1067 | 1152 |
1068 | 1153 |
1069 void StubCompiler::GenerateDictionaryLoadCallback(Register receiver, | 1154 void BaseLoadStubCompiler::GenerateLoadCallback(Register reg, |
1070 Register name_reg, | 1155 Handle<AccessorInfo> callback) { |
1071 Register scratch1, | 1156 // Insert additional parameters into the stack frame above return address. |
1072 Register scratch2, | 1157 ASSERT(!scratch3().is(reg)); |
1073 Register scratch3, | 1158 __ pop(scratch3()); // Get return address to place it below. |
1074 Handle<AccessorInfo> callback, | |
1075 Handle<String> name, | |
1076 Label* miss) { | |
1077 ASSERT(!receiver.is(scratch2)); | |
1078 ASSERT(!receiver.is(scratch3)); | |
1079 Register dictionary = scratch1; | |
1080 bool must_preserve_dictionary_reg = receiver.is(dictionary); | |
1081 | 1159 |
1082 // Load the properties dictionary. | 1160 __ push(receiver()); // receiver |
1083 if (must_preserve_dictionary_reg) { | 1161 __ mov(scratch2(), esp); |
1084 __ push(dictionary); | 1162 ASSERT(!scratch2().is(reg)); |
1085 } | |
1086 __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset)); | |
1087 | |
1088 // Probe the dictionary. | |
1089 Label probe_done, pop_and_miss; | |
1090 StringDictionaryLookupStub::GeneratePositiveLookup(masm(), | |
1091 &pop_and_miss, | |
1092 &probe_done, | |
1093 dictionary, | |
1094 name_reg, | |
1095 scratch2, | |
1096 scratch3); | |
1097 __ bind(&pop_and_miss); | |
1098 if (must_preserve_dictionary_reg) { | |
1099 __ pop(dictionary); | |
1100 } | |
1101 __ jmp(miss); | |
1102 __ bind(&probe_done); | |
1103 | |
1104 // If probing finds an entry in the dictionary, scratch2 contains the | |
1105 // index into the dictionary. Check that the value is the callback. | |
1106 Register index = scratch2; | |
1107 const int kElementsStartOffset = | |
1108 StringDictionary::kHeaderSize + | |
1109 StringDictionary::kElementsStartIndex * kPointerSize; | |
1110 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
1111 __ mov(scratch3, | |
1112 Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag)); | |
1113 if (must_preserve_dictionary_reg) { | |
1114 __ pop(dictionary); | |
1115 } | |
1116 __ cmp(scratch3, callback); | |
1117 __ j(not_equal, miss); | |
1118 } | |
1119 | |
1120 | |
1121 void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, | |
1122 Handle<JSObject> holder, | |
1123 Register receiver, | |
1124 Register name_reg, | |
1125 Register scratch1, | |
1126 Register scratch2, | |
1127 Register scratch3, | |
1128 Register scratch4, | |
1129 Handle<AccessorInfo> callback, | |
1130 Handle<String> name, | |
1131 Label* miss) { | |
1132 // Check that the receiver isn't a smi. | |
1133 __ JumpIfSmi(receiver, miss); | |
1134 | |
1135 // Check that the maps haven't changed. | |
1136 Register reg = CheckPrototypes(object, receiver, holder, scratch1, | |
1137 scratch2, scratch3, name, miss); | |
1138 | |
1139 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | |
1140 GenerateDictionaryLoadCallback( | |
1141 reg, name_reg, scratch1, scratch2, scratch3, callback, name, miss); | |
1142 } | |
1143 | |
1144 // Insert additional parameters into the stack frame above return address. | |
1145 ASSERT(!scratch3.is(reg)); | |
1146 __ pop(scratch3); // Get return address to place it below. | |
1147 | |
1148 __ push(receiver); // receiver | |
1149 __ mov(scratch2, esp); | |
1150 ASSERT(!scratch2.is(reg)); | |
1151 __ push(reg); // holder | 1163 __ push(reg); // holder |
1152 // Push data from AccessorInfo. | 1164 // Push data from AccessorInfo. |
1153 if (isolate()->heap()->InNewSpace(callback->data())) { | 1165 if (isolate()->heap()->InNewSpace(callback->data())) { |
1154 __ mov(scratch1, Immediate(callback)); | 1166 __ mov(scratch1(), Immediate(callback)); |
1155 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); | 1167 __ push(FieldOperand(scratch1(), AccessorInfo::kDataOffset)); |
1156 } else { | 1168 } else { |
1157 __ push(Immediate(Handle<Object>(callback->data()))); | 1169 __ push(Immediate(Handle<Object>(callback->data()))); |
1158 } | 1170 } |
1159 __ push(Immediate(reinterpret_cast<int>(isolate()))); | 1171 __ push(Immediate(reinterpret_cast<int>(isolate()))); |
1160 | 1172 |
1161 // Save a pointer to where we pushed the arguments pointer. | 1173 // Save a pointer to where we pushed the arguments pointer. |
1162 // This will be passed as the const AccessorInfo& to the C++ callback. | 1174 // This will be passed as the const AccessorInfo& to the C++ callback. |
1163 __ push(scratch2); | 1175 __ push(scratch2()); |
1164 | 1176 |
1165 __ push(name_reg); // name | 1177 __ push(name()); // name |
1166 __ mov(ebx, esp); // esp points to reference to name (handler). | 1178 __ mov(ebx, esp); // esp points to reference to name (handler). |
1167 | 1179 |
1168 __ push(scratch3); // Restore return address. | 1180 __ push(scratch3()); // Restore return address. |
1169 | 1181 |
1170 // 4 elements array for v8::Arguments::values_, handler for name and pointer | 1182 // 4 elements array for v8::Arguments::values_, handler for name and pointer |
1171 // to the values (it considered as smi in GC). | 1183 // to the values (it considered as smi in GC). |
1172 const int kStackSpace = 6; | 1184 const int kStackSpace = 6; |
1173 const int kApiArgc = 2; | 1185 const int kApiArgc = 2; |
1174 | 1186 |
1175 __ PrepareCallApiFunction(kApiArgc); | 1187 __ PrepareCallApiFunction(kApiArgc); |
1176 __ mov(ApiParameterOperand(0), ebx); // name. | 1188 __ mov(ApiParameterOperand(0), ebx); // name. |
1177 __ add(ebx, Immediate(kPointerSize)); | 1189 __ add(ebx, Immediate(kPointerSize)); |
1178 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. | 1190 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. |
1179 | 1191 |
1180 // Emitting a stub call may try to allocate (if the code is not | 1192 // Emitting a stub call may try to allocate (if the code is not |
1181 // already generated). Do not allow the assembler to perform a | 1193 // already generated). Do not allow the assembler to perform a |
1182 // garbage collection but instead return the allocation failure | 1194 // garbage collection but instead return the allocation failure |
1183 // object. | 1195 // object. |
1184 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1196 Address getter_address = v8::ToCData<Address>(callback->getter()); |
1185 __ CallApiFunctionAndReturn(getter_address, kStackSpace); | 1197 __ CallApiFunctionAndReturn(getter_address, kStackSpace); |
1186 } | 1198 } |
1187 | 1199 |
1188 | 1200 |
1189 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, | 1201 void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) { |
1190 Handle<JSObject> holder, | |
1191 Register receiver, | |
1192 Register scratch1, | |
1193 Register scratch2, | |
1194 Register scratch3, | |
1195 Handle<JSFunction> value, | |
1196 Handle<String> name, | |
1197 Label* miss) { | |
1198 // Check that the receiver isn't a smi. | |
1199 __ JumpIfSmi(receiver, miss); | |
1200 | |
1201 // Check that the maps haven't changed. | |
1202 CheckPrototypes( | |
1203 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | |
1204 | |
1205 // Return the constant value. | 1202 // Return the constant value. |
1206 __ LoadHeapObject(eax, value); | 1203 __ LoadHeapObject(eax, value); |
1207 __ ret(0); | 1204 __ ret(0); |
1208 } | 1205 } |
1209 | 1206 |
1210 | 1207 |
1211 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, | 1208 void BaseLoadStubCompiler::GenerateLoadInterceptor( |
1212 Handle<JSObject> interceptor_holder, | 1209 Register holder_reg, |
1213 LookupResult* lookup, | 1210 Handle<JSObject> object, |
1214 Register receiver, | 1211 Handle<JSObject> interceptor_holder, |
1215 Register name_reg, | 1212 LookupResult* lookup, |
1216 Register scratch1, | 1213 Handle<String> name) { |
1217 Register scratch2, | |
1218 Register scratch3, | |
1219 Handle<String> name, | |
1220 Label* miss) { | |
1221 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1214 ASSERT(interceptor_holder->HasNamedInterceptor()); |
1222 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 1215 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
1223 | 1216 |
1224 // Check that the receiver isn't a smi. | |
1225 __ JumpIfSmi(receiver, miss); | |
1226 | |
1227 // So far the most popular follow ups for interceptor loads are FIELD | 1217 // So far the most popular follow ups for interceptor loads are FIELD |
1228 // and CALLBACKS, so inline only them, other cases may be added | 1218 // and CALLBACKS, so inline only them, other cases may be added |
1229 // later. | 1219 // later. |
1230 bool compile_followup_inline = false; | 1220 bool compile_followup_inline = false; |
1231 if (lookup->IsFound() && lookup->IsCacheable()) { | 1221 if (lookup->IsFound() && lookup->IsCacheable()) { |
1232 if (lookup->IsField()) { | 1222 if (lookup->IsField()) { |
1233 compile_followup_inline = true; | 1223 compile_followup_inline = true; |
1234 } else if (lookup->type() == CALLBACKS && | 1224 } else if (lookup->type() == CALLBACKS && |
1235 lookup->GetCallbackObject()->IsAccessorInfo()) { | 1225 lookup->GetCallbackObject()->IsAccessorInfo()) { |
1236 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1226 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
1237 compile_followup_inline = callback->getter() != NULL && | 1227 compile_followup_inline = callback->getter() != NULL && |
1238 callback->IsCompatibleReceiver(*object); | 1228 callback->IsCompatibleReceiver(*object); |
1239 } | 1229 } |
1240 } | 1230 } |
1241 | 1231 |
1242 if (compile_followup_inline) { | 1232 if (compile_followup_inline) { |
1243 // Compile the interceptor call, followed by inline code to load the | 1233 // Compile the interceptor call, followed by inline code to load the |
1244 // property from further up the prototype chain if the call fails. | 1234 // property from further up the prototype chain if the call fails. |
1245 // Check that the maps haven't changed. | 1235 // Check that the maps haven't changed. |
1246 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1236 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
1247 scratch1, scratch2, scratch3, | |
1248 name, miss); | |
1249 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); | |
1250 | 1237 |
1251 // Preserve the receiver register explicitly whenever it is different from | 1238 // Preserve the receiver register explicitly whenever it is different from |
1252 // the holder and it is needed should the interceptor return without any | 1239 // the holder and it is needed should the interceptor return without any |
1253 // result. The CALLBACKS case needs the receiver to be passed into C++ code, | 1240 // result. The CALLBACKS case needs the receiver to be passed into C++ code, |
1254 // the FIELD case might cause a miss during the prototype check. | 1241 // the FIELD case might cause a miss during the prototype check. |
1255 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); | 1242 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); |
1256 bool must_preserve_receiver_reg = !receiver.is(holder_reg) && | 1243 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
1257 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); | 1244 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
1258 | 1245 |
1259 // Save necessary data before invoking an interceptor. | 1246 // Save necessary data before invoking an interceptor. |
1260 // Requires a frame to make GC aware of pushed pointers. | 1247 // Requires a frame to make GC aware of pushed pointers. |
1261 { | 1248 { |
1262 FrameScope frame_scope(masm(), StackFrame::INTERNAL); | 1249 FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
1263 | 1250 |
1264 if (must_preserve_receiver_reg) { | 1251 if (must_preserve_receiver_reg) { |
1265 __ push(receiver); | 1252 __ push(receiver()); |
1266 } | 1253 } |
1267 __ push(holder_reg); | 1254 __ push(holder_reg); |
1268 __ push(name_reg); | 1255 __ push(this->name()); |
1269 | 1256 |
1270 // Invoke an interceptor. Note: map checks from receiver to | 1257 // Invoke an interceptor. Note: map checks from receiver to |
1271 // interceptor's holder has been compiled before (see a caller | 1258 // interceptor's holder has been compiled before (see a caller |
1272 // of this method.) | 1259 // of this method.) |
1273 CompileCallLoadPropertyWithInterceptor(masm(), | 1260 CompileCallLoadPropertyWithInterceptor(masm(), |
1274 receiver, | 1261 receiver(), |
1275 holder_reg, | 1262 holder_reg, |
1276 name_reg, | 1263 this->name(), |
1277 interceptor_holder); | 1264 interceptor_holder); |
1278 | 1265 |
1279 // Check if interceptor provided a value for property. If it's | 1266 // Check if interceptor provided a value for property. If it's |
1280 // the case, return immediately. | 1267 // the case, return immediately. |
1281 Label interceptor_failed; | 1268 Label interceptor_failed; |
1282 __ cmp(eax, factory()->no_interceptor_result_sentinel()); | 1269 __ cmp(eax, factory()->no_interceptor_result_sentinel()); |
1283 __ j(equal, &interceptor_failed); | 1270 __ j(equal, &interceptor_failed); |
1284 frame_scope.GenerateLeaveFrame(); | 1271 frame_scope.GenerateLeaveFrame(); |
1285 __ ret(0); | 1272 __ ret(0); |
1286 | 1273 |
1287 // Clobber registers when generating debug-code to provoke errors. | 1274 // Clobber registers when generating debug-code to provoke errors. |
1288 __ bind(&interceptor_failed); | 1275 __ bind(&interceptor_failed); |
1289 if (FLAG_debug_code) { | 1276 if (FLAG_debug_code) { |
1290 __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue))); | 1277 __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue))); |
1291 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue))); | 1278 __ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue))); |
1292 __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue))); | 1279 __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue))); |
1293 } | 1280 } |
1294 | 1281 |
1295 __ pop(name_reg); | 1282 __ pop(this->name()); |
1296 __ pop(holder_reg); | 1283 __ pop(holder_reg); |
1297 if (must_preserve_receiver_reg) { | 1284 if (must_preserve_receiver_reg) { |
1298 __ pop(receiver); | 1285 __ pop(receiver()); |
1299 } | 1286 } |
1300 | 1287 |
1301 // Leave the internal frame. | 1288 // Leave the internal frame. |
1302 } | 1289 } |
1303 | 1290 |
1304 // Check that the maps from interceptor's holder to lookup's holder | 1291 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup); |
1305 // haven't changed. And load lookup's holder into holder_reg. | |
1306 if (must_perfrom_prototype_check) { | |
1307 holder_reg = CheckPrototypes(interceptor_holder, | |
1308 holder_reg, | |
1309 Handle<JSObject>(lookup->holder()), | |
1310 scratch1, | |
1311 scratch2, | |
1312 scratch3, | |
1313 name, | |
1314 miss); | |
1315 } | |
1316 | |
1317 if (lookup->IsField()) { | |
1318 // We found FIELD property in prototype chain of interceptor's holder. | |
1319 // Retrieve a field from field's holder. | |
1320 GenerateFastPropertyLoad(masm(), eax, holder_reg, | |
1321 Handle<JSObject>(lookup->holder()), | |
1322 lookup->GetFieldIndex()); | |
1323 __ ret(0); | |
1324 } else { | |
1325 // We found CALLBACKS property in prototype chain of interceptor's | |
1326 // holder. | |
1327 ASSERT(lookup->type() == CALLBACKS); | |
1328 Handle<AccessorInfo> callback( | |
1329 AccessorInfo::cast(lookup->GetCallbackObject())); | |
1330 ASSERT(callback->getter() != NULL); | |
1331 | |
1332 // Tail call to runtime. | |
1333 // Important invariant in CALLBACKS case: the code above must be | |
1334 // structured to never clobber |receiver| register. | |
1335 __ pop(scratch2); // return address | |
1336 __ push(receiver); | |
1337 __ push(holder_reg); | |
1338 __ mov(holder_reg, Immediate(callback)); | |
1339 __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); | |
1340 __ push(Immediate(reinterpret_cast<int>(isolate()))); | |
1341 __ push(holder_reg); | |
1342 __ push(name_reg); | |
1343 __ push(scratch2); // restore return address | |
1344 | |
1345 ExternalReference ref = | |
1346 ExternalReference(IC_Utility(IC::kLoadCallbackProperty), | |
1347 masm()->isolate()); | |
1348 __ TailCallExternalReference(ref, 6, 1); | |
1349 } | |
1350 } else { // !compile_followup_inline | 1292 } else { // !compile_followup_inline |
1351 // Call the runtime system to load the interceptor. | 1293 // Call the runtime system to load the interceptor. |
1352 // Check that the maps haven't changed. | 1294 // Check that the maps haven't changed. |
1353 Register holder_reg = | 1295 __ pop(scratch2()); // save old return address |
1354 CheckPrototypes(object, receiver, interceptor_holder, | 1296 PushInterceptorArguments(masm(), receiver(), holder_reg, |
1355 scratch1, scratch2, scratch3, name, miss); | 1297 this->name(), interceptor_holder); |
1356 __ pop(scratch2); // save old return address | 1298 __ push(scratch2()); // restore old return address |
1357 PushInterceptorArguments(masm(), receiver, holder_reg, | |
1358 name_reg, interceptor_holder); | |
1359 __ push(scratch2); // restore old return address | |
1360 | 1299 |
1361 ExternalReference ref = | 1300 ExternalReference ref = |
1362 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1301 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
1363 isolate()); | 1302 isolate()); |
1364 __ TailCallExternalReference(ref, 6, 1); | 1303 __ TailCallExternalReference(ref, 6, 1); |
1365 } | 1304 } |
1366 } | 1305 } |
1367 | 1306 |
1368 | 1307 |
1369 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { | 1308 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { |
(...skipping 1594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2964 // Return the generated code. | 2903 // Return the generated code. |
2965 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC); | 2904 return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC); |
2966 } | 2905 } |
2967 | 2906 |
2968 | 2907 |
2969 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( | 2908 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( |
2970 Handle<JSObject> object, | 2909 Handle<JSObject> object, |
2971 Handle<JSObject> last, | 2910 Handle<JSObject> last, |
2972 Handle<String> name, | 2911 Handle<String> name, |
2973 Handle<GlobalObject> global) { | 2912 Handle<GlobalObject> global) { |
2974 // ----------- S t a t e ------------- | 2913 Label success; |
2975 // -- ecx : name | |
2976 // -- edx : receiver | |
2977 // -- esp[0] : return address | |
2978 // ----------------------------------- | |
2979 Label miss; | |
2980 | 2914 |
2981 // Check that the receiver isn't a smi. | 2915 NonexistentHandlerFrontend(object, last, name, &success, global); |
2982 __ JumpIfSmi(edx, &miss); | |
2983 | 2916 |
2984 Register scratch = eax; | 2917 __ bind(&success); |
2985 | |
2986 // Check the maps of the full prototype chain. Also check that | |
2987 // global property cells up to (but not including) the last object | |
2988 // in the prototype chain are empty. | |
2989 Register result = | |
2990 CheckPrototypes(object, edx, last, ebx, scratch, edi, name, &miss); | |
2991 | |
2992 // If the last object in the prototype chain is a global object, | |
2993 // check that the global property cell is empty. | |
2994 if (!global.is_null()) { | |
2995 GenerateCheckPropertyCell(masm(), global, name, scratch, &miss); | |
2996 } | |
2997 | |
2998 if (!last->HasFastProperties()) { | |
2999 __ mov(scratch, FieldOperand(result, HeapObject::kMapOffset)); | |
3000 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); | |
3001 __ cmp(scratch, isolate()->factory()->null_value()); | |
3002 __ j(not_equal, &miss); | |
3003 } | |
3004 | |
3005 // Return undefined if maps of the full prototype chain are still the | 2918 // Return undefined if maps of the full prototype chain are still the |
3006 // same and no global property with this name contains a value. | 2919 // same and no global property with this name contains a value. |
3007 __ mov(eax, isolate()->factory()->undefined_value()); | 2920 __ mov(eax, isolate()->factory()->undefined_value()); |
3008 __ ret(0); | 2921 __ ret(0); |
3009 | 2922 |
3010 __ bind(&miss); | |
3011 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
3012 | |
3013 // Return the generated code. | 2923 // Return the generated code. |
3014 return GetCode(Code::NONEXISTENT, factory()->empty_string()); | 2924 return GetCode(Code::NONEXISTENT, factory()->empty_string()); |
3015 } | 2925 } |
3016 | 2926 |
3017 | 2927 |
3018 Register* LoadStubCompiler::registers() { | 2928 Register* LoadStubCompiler::registers() { |
3019 // receiver, name, scratch1, scratch2, scratch3, scratch4. | 2929 // receiver, name, scratch1, scratch2, scratch3, scratch4. |
3020 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg }; | 2930 static Register registers[] = { edx, ecx, ebx, eax, edi, no_reg }; |
3021 return registers; | 2931 return registers; |
3022 } | 2932 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3067 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2977 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
3068 } | 2978 } |
3069 __ ret(0); | 2979 __ ret(0); |
3070 } | 2980 } |
3071 | 2981 |
3072 | 2982 |
3073 #undef __ | 2983 #undef __ |
3074 #define __ ACCESS_MASM(masm()) | 2984 #define __ ACCESS_MASM(masm()) |
3075 | 2985 |
3076 | 2986 |
3077 Handle<Code> LoadStubCompiler::CompileLoadViaGetter( | |
3078 Handle<JSObject> receiver, | |
3079 Handle<JSObject> holder, | |
3080 Handle<String> name, | |
3081 Handle<JSFunction> getter) { | |
3082 // ----------- S t a t e ------------- | |
3083 // -- ecx : name | |
3084 // -- edx : receiver | |
3085 // -- esp[0] : return address | |
3086 // ----------------------------------- | |
3087 Label miss; | |
3088 | |
3089 // Check that the maps haven't changed. | |
3090 __ JumpIfSmi(edx, &miss); | |
3091 CheckPrototypes(receiver, edx, holder, ebx, eax, edi, name, &miss); | |
3092 | |
3093 GenerateLoadViaGetter(masm(), getter); | |
3094 | |
3095 __ bind(&miss); | |
3096 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
3097 | |
3098 // Return the generated code. | |
3099 return GetCode(Code::CALLBACKS, name); | |
3100 } | |
3101 | |
3102 | |
3103 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2987 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
3104 Handle<JSObject> object, | 2988 Handle<JSObject> object, |
3105 Handle<GlobalObject> holder, | 2989 Handle<GlobalObject> global, |
3106 Handle<JSGlobalPropertyCell> cell, | 2990 Handle<JSGlobalPropertyCell> cell, |
3107 Handle<String> name, | 2991 Handle<String> name, |
3108 bool is_dont_delete) { | 2992 bool is_dont_delete) { |
3109 // ----------- S t a t e ------------- | 2993 Label success, miss; |
3110 // -- ecx : name | |
3111 // -- edx : receiver | |
3112 // -- esp[0] : return address | |
3113 // ----------------------------------- | |
3114 Label miss; | |
3115 | 2994 |
3116 // Check that the maps haven't changed. | 2995 HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global), |
3117 __ JumpIfSmi(edx, &miss); | 2996 name, &miss, PERFORM_INITIAL_CHECKS); |
3118 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, &miss); | |
3119 | |
3120 // Get the value from the cell. | 2997 // Get the value from the cell. |
3121 if (Serializer::enabled()) { | 2998 if (Serializer::enabled()) { |
3122 __ mov(ebx, Immediate(cell)); | 2999 __ mov(eax, Immediate(cell)); |
3123 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | 3000 __ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset)); |
3124 } else { | 3001 } else { |
3125 __ mov(ebx, Operand::Cell(cell)); | 3002 __ mov(eax, Operand::Cell(cell)); |
3126 } | 3003 } |
3127 | 3004 |
3128 // Check for deleted property if property can actually be deleted. | 3005 // Check for deleted property if property can actually be deleted. |
3129 if (!is_dont_delete) { | 3006 if (!is_dont_delete) { |
3130 __ cmp(ebx, factory()->the_hole_value()); | 3007 __ cmp(eax, factory()->the_hole_value()); |
3131 __ j(equal, &miss); | 3008 __ j(equal, &miss); |
3132 } else if (FLAG_debug_code) { | 3009 } else if (FLAG_debug_code) { |
3133 __ cmp(ebx, factory()->the_hole_value()); | 3010 __ cmp(eax, factory()->the_hole_value()); |
3134 __ Check(not_equal, "DontDelete cells can't contain the hole"); | 3011 __ Check(not_equal, "DontDelete cells can't contain the hole"); |
3135 } | 3012 } |
3136 | 3013 |
| 3014 HandlerFrontendFooter(&success, &miss); |
| 3015 __ bind(&success); |
| 3016 |
3137 Counters* counters = isolate()->counters(); | 3017 Counters* counters = isolate()->counters(); |
3138 __ IncrementCounter(counters->named_load_global_stub(), 1); | 3018 __ IncrementCounter(counters->named_load_global_stub(), 1); |
3139 __ mov(eax, ebx); | 3019 // The code above already loads the result into the return register. |
3140 __ ret(0); | 3020 __ ret(0); |
3141 | 3021 |
3142 __ bind(&miss); | |
3143 __ IncrementCounter(counters->named_load_global_stub_miss(), 1); | |
3144 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
3145 | |
3146 // Return the generated code. | 3022 // Return the generated code. |
3147 return GetCode(Code::NORMAL, name); | 3023 return GetCode(Code::NORMAL, name); |
3148 } | 3024 } |
3149 | 3025 |
3150 | 3026 |
3151 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( | 3027 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( |
3152 Handle<Map> receiver_map) { | 3028 Handle<Map> receiver_map) { |
3153 // ----------- S t a t e ------------- | 3029 // ----------- S t a t e ------------- |
3154 // -- ecx : key | 3030 // -- ecx : key |
3155 // -- edx : receiver | 3031 // -- edx : receiver |
(...skipping 763 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3919 __ jmp(ic_slow, RelocInfo::CODE_TARGET); | 3795 __ jmp(ic_slow, RelocInfo::CODE_TARGET); |
3920 } | 3796 } |
3921 } | 3797 } |
3922 | 3798 |
3923 | 3799 |
3924 #undef __ | 3800 #undef __ |
3925 | 3801 |
3926 } } // namespace v8::internal | 3802 } } // namespace v8::internal |
3927 | 3803 |
3928 #endif // V8_TARGET_ARCH_IA32 | 3804 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |