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