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