Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/ia32/stub-cache-ia32.cc

Issue 12209021: Refactor LoadIC into Handler Frontend and Backends. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/ic.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | src/ic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698