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 1150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1161 // If we've skipped any global objects, it's not enough to verify that | 1161 // If we've skipped any global objects, it's not enough to verify that |
1162 // their maps haven't changed. We also need to check that the property | 1162 // their maps haven't changed. We also need to check that the property |
1163 // cell for the property is still empty. | 1163 // cell for the property is still empty. |
1164 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); | 1164 GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss); |
1165 | 1165 |
1166 // Return the register containing the holder. | 1166 // Return the register containing the holder. |
1167 return reg; | 1167 return reg; |
1168 } | 1168 } |
1169 | 1169 |
1170 | 1170 |
1171 void StubCompiler::GenerateLoadField(Handle<JSObject> object, | 1171 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success, |
1172 Handle<JSObject> holder, | 1172 Label* miss) { |
1173 Register receiver, | 1173 __ Branch(success); |
1174 Register scratch1, | 1174 __ bind(miss); |
1175 Register scratch2, | 1175 GenerateLoadMiss(masm(), kind()); |
1176 Register scratch3, | 1176 } |
1177 PropertyIndex index, | |
1178 Handle<String> name, | |
1179 Label* miss) { | |
1180 // Check that the receiver isn't a smi. | |
1181 __ JumpIfSmi(receiver, miss); | |
1182 | 1177 |
1183 // Check that the maps haven't changed. | 1178 |
1184 Register reg = CheckPrototypes( | 1179 Register BaseLoadStubCompiler::CallbackHandlerFrontend( |
1185 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | 1180 Handle<JSObject> object, |
| 1181 Register object_reg, |
| 1182 Handle<JSObject> holder, |
| 1183 Handle<String> name, |
| 1184 Label* success, |
| 1185 FrontendCheckType check, |
| 1186 Handle<ExecutableAccessorInfo> callback) { |
| 1187 Label miss; |
| 1188 |
| 1189 Register reg = HandlerFrontendHeader( |
| 1190 object, object_reg, holder, name, &miss, check); |
| 1191 |
| 1192 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 1193 ASSERT(!reg.is(scratch2())); |
| 1194 ASSERT(!reg.is(scratch3())); |
| 1195 ASSERT(!reg.is(scratch4())); |
| 1196 |
| 1197 // Load the properties dictionary. |
| 1198 Register dictionary = scratch4(); |
| 1199 __ lw(dictionary, FieldMemOperand(reg, JSObject::kPropertiesOffset)); |
| 1200 |
| 1201 // Probe the dictionary. |
| 1202 Label probe_done; |
| 1203 StringDictionaryLookupStub::GeneratePositiveLookup(masm(), |
| 1204 &miss, |
| 1205 &probe_done, |
| 1206 dictionary, |
| 1207 this->name(), |
| 1208 scratch2(), |
| 1209 scratch3()); |
| 1210 __ bind(&probe_done); |
| 1211 |
| 1212 // If probing finds an entry in the dictionary, scratch3 contains the |
| 1213 // pointer into the dictionary. Check that the value is the callback. |
| 1214 Register pointer = scratch3(); |
| 1215 const int kElementsStartOffset = StringDictionary::kHeaderSize + |
| 1216 StringDictionary::kElementsStartIndex * kPointerSize; |
| 1217 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 1218 __ lw(scratch2(), FieldMemOperand(pointer, kValueOffset)); |
| 1219 __ Branch(&miss, ne, scratch2(), Operand(callback)); |
| 1220 } |
| 1221 |
| 1222 HandlerFrontendFooter(success, &miss); |
| 1223 return reg; |
| 1224 } |
| 1225 |
| 1226 |
| 1227 void BaseLoadStubCompiler::NonexistentHandlerFrontend( |
| 1228 Handle<JSObject> object, |
| 1229 Handle<JSObject> last, |
| 1230 Handle<String> name, |
| 1231 Label* success, |
| 1232 Handle<GlobalObject> global) { |
| 1233 Label miss; |
| 1234 |
| 1235 Register reg = HandlerFrontendHeader( |
| 1236 object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS); |
| 1237 |
| 1238 // If the last object in the prototype chain is a global object, |
| 1239 // check that the global property cell is empty. |
| 1240 if (!global.is_null()) { |
| 1241 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); |
| 1242 } |
| 1243 |
| 1244 if (!last->HasFastProperties()) { |
| 1245 __ lw(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 1246 __ lw(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset)); |
| 1247 __ Branch(&miss, ne, scratch2(), |
| 1248 Operand(isolate()->factory()->null_value())); |
| 1249 } |
| 1250 |
| 1251 HandlerFrontendFooter(success, &miss); |
| 1252 } |
| 1253 |
| 1254 |
| 1255 void BaseLoadStubCompiler::GenerateLoadField(Register reg, |
| 1256 Handle<JSObject> holder, |
| 1257 PropertyIndex index) { |
1186 GenerateFastPropertyLoad(masm(), v0, reg, holder, index); | 1258 GenerateFastPropertyLoad(masm(), v0, reg, holder, index); |
1187 __ Ret(); | 1259 __ Ret(); |
1188 } | 1260 } |
1189 | 1261 |
1190 | 1262 |
1191 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, | 1263 void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) { |
1192 Handle<JSObject> holder, | |
1193 Register receiver, | |
1194 Register scratch1, | |
1195 Register scratch2, | |
1196 Register scratch3, | |
1197 Handle<JSFunction> value, | |
1198 Handle<String> name, | |
1199 Label* miss) { | |
1200 // Check that the receiver isn't a smi. | |
1201 __ JumpIfSmi(receiver, miss, scratch1); | |
1202 | |
1203 // Check that the maps haven't changed. | |
1204 CheckPrototypes(object, receiver, holder, | |
1205 scratch1, scratch2, scratch3, name, miss); | |
1206 | |
1207 // Return the constant value. | 1264 // Return the constant value. |
1208 __ LoadHeapObject(v0, value); | 1265 __ LoadHeapObject(v0, value); |
1209 __ Ret(); | 1266 __ Ret(); |
1210 } | 1267 } |
1211 | 1268 |
1212 | 1269 |
1213 void StubCompiler::GenerateDictionaryLoadCallback( | 1270 void BaseLoadStubCompiler::GenerateLoadCallback( |
1214 Register receiver, | 1271 Register reg, |
1215 Register name_reg, | 1272 Handle<ExecutableAccessorInfo> callback) { |
1216 Register scratch1, | |
1217 Register scratch2, | |
1218 Register scratch3, | |
1219 Handle<ExecutableAccessorInfo> callback, | |
1220 Handle<String> name, | |
1221 Label* miss) { | |
1222 ASSERT(!receiver.is(scratch1)); | |
1223 ASSERT(!receiver.is(scratch2)); | |
1224 ASSERT(!receiver.is(scratch3)); | |
1225 | |
1226 // Load the properties dictionary. | |
1227 Register dictionary = scratch1; | |
1228 __ lw(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | |
1229 | |
1230 // Probe the dictionary. | |
1231 Label probe_done; | |
1232 StringDictionaryLookupStub::GeneratePositiveLookup(masm(), | |
1233 miss, | |
1234 &probe_done, | |
1235 dictionary, | |
1236 name_reg, | |
1237 scratch2, | |
1238 scratch3); | |
1239 __ bind(&probe_done); | |
1240 | |
1241 // If probing finds an entry in the dictionary, scratch3 contains the | |
1242 // pointer into the dictionary. Check that the value is the callback. | |
1243 Register pointer = scratch3; | |
1244 const int kElementsStartOffset = StringDictionary::kHeaderSize + | |
1245 StringDictionary::kElementsStartIndex * kPointerSize; | |
1246 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
1247 __ lw(scratch2, FieldMemOperand(pointer, kValueOffset)); | |
1248 __ Branch(miss, ne, scratch2, Operand(callback)); | |
1249 } | |
1250 | |
1251 | |
1252 void StubCompiler::GenerateLoadCallback( | |
1253 Handle<JSObject> object, | |
1254 Handle<JSObject> holder, | |
1255 Register receiver, | |
1256 Register name_reg, | |
1257 Register scratch1, | |
1258 Register scratch2, | |
1259 Register scratch3, | |
1260 Register scratch4, | |
1261 Handle<ExecutableAccessorInfo> callback, | |
1262 Handle<String> name, | |
1263 Label* miss) { | |
1264 // Check that the receiver isn't a smi. | |
1265 __ JumpIfSmi(receiver, miss, scratch1); | |
1266 | |
1267 // Check that the maps haven't changed. | |
1268 Register reg = CheckPrototypes(object, receiver, holder, scratch1, | |
1269 scratch2, scratch3, name, miss); | |
1270 | |
1271 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | |
1272 GenerateDictionaryLoadCallback( | |
1273 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss); | |
1274 } | |
1275 | |
1276 // Build AccessorInfo::args_ list on the stack and push property name below | 1273 // Build AccessorInfo::args_ list on the stack and push property name below |
1277 // the exit frame to make GC aware of them and store pointers to them. | 1274 // the exit frame to make GC aware of them and store pointers to them. |
1278 __ push(receiver); | 1275 __ push(receiver()); |
1279 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_ | 1276 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_ |
1280 if (heap()->InNewSpace(callback->data())) { | 1277 if (heap()->InNewSpace(callback->data())) { |
1281 __ li(scratch3, callback); | 1278 __ li(scratch3(), callback); |
1282 __ lw(scratch3, | 1279 __ lw(scratch3(), FieldMemOperand(scratch3(), |
1283 FieldMemOperand(scratch3, ExecutableAccessorInfo::kDataOffset)); | 1280 ExecutableAccessorInfo::kDataOffset)); |
1284 } else { | 1281 } else { |
1285 __ li(scratch3, Handle<Object>(callback->data(), masm()->isolate())); | 1282 __ li(scratch3(), Handle<Object>(callback->data(), |
| 1283 callback->GetIsolate())); |
1286 } | 1284 } |
1287 __ Subu(sp, sp, 4 * kPointerSize); | 1285 __ Subu(sp, sp, 4 * kPointerSize); |
1288 __ sw(reg, MemOperand(sp, 3 * kPointerSize)); | 1286 __ sw(reg, MemOperand(sp, 3 * kPointerSize)); |
1289 __ sw(scratch3, MemOperand(sp, 2 * kPointerSize)); | 1287 __ sw(scratch3(), MemOperand(sp, 2 * kPointerSize)); |
1290 __ li(scratch3, Operand(ExternalReference::isolate_address())); | 1288 __ li(scratch3(), Operand(ExternalReference::isolate_address())); |
1291 __ sw(scratch3, MemOperand(sp, 1 * kPointerSize)); | 1289 __ sw(scratch3(), MemOperand(sp, 1 * kPointerSize)); |
1292 __ sw(name_reg, MemOperand(sp, 0 * kPointerSize)); | 1290 __ sw(name(), MemOperand(sp, 0 * kPointerSize)); |
1293 | 1291 |
1294 __ mov(a2, scratch2); // Saved in case scratch2 == a1. | 1292 __ mov(a2, scratch2()); // Saved in case scratch2 == a1. |
1295 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String> | 1293 __ mov(a1, sp); // a1 (first argument - see note below) = Handle<String> |
1296 | 1294 |
1297 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a | 1295 // NOTE: the O32 abi requires a0 to hold a special pointer when returning a |
1298 // struct from the function (which is currently the case). This means we pass | 1296 // struct from the function (which is currently the case). This means we pass |
1299 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn | 1297 // the arguments in a1-a2 instead of a0-a1. TryCallApiFunctionAndReturn |
1300 // will handle setting up a0. | 1298 // will handle setting up a0. |
1301 | 1299 |
1302 const int kApiStackSpace = 1; | 1300 const int kApiStackSpace = 1; |
1303 FrameScope frame_scope(masm(), StackFrame::MANUAL); | 1301 FrameScope frame_scope(masm(), StackFrame::MANUAL); |
1304 __ EnterExitFrame(false, kApiStackSpace); | 1302 __ EnterExitFrame(false, kApiStackSpace); |
1305 | 1303 |
1306 // Create AccessorInfo instance on the stack above the exit frame with | 1304 // Create AccessorInfo instance on the stack above the exit frame with |
1307 // scratch2 (internal::Object** args_) as the data. | 1305 // scratch2 (internal::Object** args_) as the data. |
1308 __ sw(a2, MemOperand(sp, kPointerSize)); | 1306 __ sw(a2, MemOperand(sp, kPointerSize)); |
1309 // a2 (second argument - see note above) = AccessorInfo& | 1307 // a2 (second argument - see note above) = AccessorInfo& |
1310 __ Addu(a2, sp, kPointerSize); | 1308 __ Addu(a2, sp, kPointerSize); |
1311 | 1309 |
1312 const int kStackUnwindSpace = 5; | 1310 const int kStackUnwindSpace = 5; |
1313 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1311 Address getter_address = v8::ToCData<Address>(callback->getter()); |
1314 ApiFunction fun(getter_address); | 1312 ApiFunction fun(getter_address); |
1315 ExternalReference ref = | 1313 ExternalReference ref = |
1316 ExternalReference(&fun, | 1314 ExternalReference(&fun, |
1317 ExternalReference::DIRECT_GETTER_CALL, | 1315 ExternalReference::DIRECT_GETTER_CALL, |
1318 masm()->isolate()); | 1316 masm()->isolate()); |
1319 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace); | 1317 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace); |
1320 } | 1318 } |
1321 | 1319 |
1322 | 1320 |
1323 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, | 1321 void BaseLoadStubCompiler::GenerateLoadInterceptor( |
1324 Handle<JSObject> interceptor_holder, | 1322 Register holder_reg, |
1325 LookupResult* lookup, | 1323 Handle<JSObject> object, |
1326 Register receiver, | 1324 Handle<JSObject> interceptor_holder, |
1327 Register name_reg, | 1325 LookupResult* lookup, |
1328 Register scratch1, | 1326 Handle<String> name) { |
1329 Register scratch2, | |
1330 Register scratch3, | |
1331 Handle<String> name, | |
1332 Label* miss) { | |
1333 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1327 ASSERT(interceptor_holder->HasNamedInterceptor()); |
1334 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 1328 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
1335 | 1329 |
1336 // Check that the receiver isn't a smi. | |
1337 __ JumpIfSmi(receiver, miss); | |
1338 | |
1339 // So far the most popular follow ups for interceptor loads are FIELD | 1330 // So far the most popular follow ups for interceptor loads are FIELD |
1340 // and CALLBACKS, so inline only them, other cases may be added | 1331 // and CALLBACKS, so inline only them, other cases may be added |
1341 // later. | 1332 // later. |
1342 bool compile_followup_inline = false; | 1333 bool compile_followup_inline = false; |
1343 if (lookup->IsFound() && lookup->IsCacheable()) { | 1334 if (lookup->IsFound() && lookup->IsCacheable()) { |
1344 if (lookup->IsField()) { | 1335 if (lookup->IsField()) { |
1345 compile_followup_inline = true; | 1336 compile_followup_inline = true; |
1346 } else if (lookup->type() == CALLBACKS && | 1337 } else if (lookup->type() == CALLBACKS && |
1347 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { | 1338 lookup->GetCallbackObject()->IsExecutableAccessorInfo()) { |
1348 ExecutableAccessorInfo* callback = | 1339 ExecutableAccessorInfo* callback = |
1349 ExecutableAccessorInfo::cast(lookup->GetCallbackObject()); | 1340 ExecutableAccessorInfo::cast(lookup->GetCallbackObject()); |
1350 compile_followup_inline = callback->getter() != NULL && | 1341 compile_followup_inline = callback->getter() != NULL && |
1351 callback->IsCompatibleReceiver(*object); | 1342 callback->IsCompatibleReceiver(*object); |
1352 } | 1343 } |
1353 } | 1344 } |
1354 | 1345 |
1355 if (compile_followup_inline) { | 1346 if (compile_followup_inline) { |
1356 // Compile the interceptor call, followed by inline code to load the | 1347 // Compile the interceptor call, followed by inline code to load the |
1357 // property from further up the prototype chain if the call fails. | 1348 // property from further up the prototype chain if the call fails. |
1358 // Check that the maps haven't changed. | 1349 // Check that the maps haven't changed. |
1359 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1350 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
1360 scratch1, scratch2, scratch3, | |
1361 name, miss); | |
1362 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); | |
1363 | 1351 |
1364 // Preserve the receiver register explicitly whenever it is different from | 1352 // Preserve the receiver register explicitly whenever it is different from |
1365 // the holder and it is needed should the interceptor return without any | 1353 // the holder and it is needed should the interceptor return without any |
1366 // result. The CALLBACKS case needs the receiver to be passed into C++ code, | 1354 // result. The CALLBACKS case needs the receiver to be passed into C++ code, |
1367 // the FIELD case might cause a miss during the prototype check. | 1355 // the FIELD case might cause a miss during the prototype check. |
1368 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); | 1356 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); |
1369 bool must_preserve_receiver_reg = !receiver.is(holder_reg) && | 1357 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
1370 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); | 1358 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
1371 | 1359 |
1372 // Save necessary data before invoking an interceptor. | 1360 // Save necessary data before invoking an interceptor. |
1373 // Requires a frame to make GC aware of pushed pointers. | 1361 // Requires a frame to make GC aware of pushed pointers. |
1374 { | 1362 { |
1375 FrameScope frame_scope(masm(), StackFrame::INTERNAL); | 1363 FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
1376 if (must_preserve_receiver_reg) { | 1364 if (must_preserve_receiver_reg) { |
1377 __ Push(receiver, holder_reg, name_reg); | 1365 __ Push(receiver(), holder_reg, this->name()); |
1378 } else { | 1366 } else { |
1379 __ Push(holder_reg, name_reg); | 1367 __ Push(holder_reg, this->name()); |
1380 } | 1368 } |
1381 // Invoke an interceptor. Note: map checks from receiver to | 1369 // Invoke an interceptor. Note: map checks from receiver to |
1382 // interceptor's holder has been compiled before (see a caller | 1370 // interceptor's holder has been compiled before (see a caller |
1383 // of this method). | 1371 // of this method). |
1384 CompileCallLoadPropertyWithInterceptor(masm(), | 1372 CompileCallLoadPropertyWithInterceptor(masm(), |
1385 receiver, | 1373 receiver(), |
1386 holder_reg, | 1374 holder_reg, |
1387 name_reg, | 1375 this->name(), |
1388 interceptor_holder); | 1376 interceptor_holder); |
1389 // Check if interceptor provided a value for property. If it's | 1377 // Check if interceptor provided a value for property. If it's |
1390 // the case, return immediately. | 1378 // the case, return immediately. |
1391 Label interceptor_failed; | 1379 Label interceptor_failed; |
1392 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); | 1380 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); |
1393 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1)); | 1381 __ Branch(&interceptor_failed, eq, v0, Operand(scratch1())); |
1394 frame_scope.GenerateLeaveFrame(); | 1382 frame_scope.GenerateLeaveFrame(); |
1395 __ Ret(); | 1383 __ Ret(); |
1396 | 1384 |
1397 __ bind(&interceptor_failed); | 1385 __ bind(&interceptor_failed); |
1398 __ pop(name_reg); | 1386 __ pop(this->name()); |
1399 __ pop(holder_reg); | 1387 __ pop(holder_reg); |
1400 if (must_preserve_receiver_reg) { | 1388 if (must_preserve_receiver_reg) { |
1401 __ pop(receiver); | 1389 __ pop(receiver()); |
1402 } | 1390 } |
1403 // Leave the internal frame. | 1391 // Leave the internal frame. |
1404 } | 1392 } |
1405 // Check that the maps from interceptor's holder to lookup's holder | 1393 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup); |
1406 // haven't changed. And load lookup's holder into |holder| register. | |
1407 if (must_perfrom_prototype_check) { | |
1408 holder_reg = CheckPrototypes(interceptor_holder, | |
1409 holder_reg, | |
1410 Handle<JSObject>(lookup->holder()), | |
1411 scratch1, | |
1412 scratch2, | |
1413 scratch3, | |
1414 name, | |
1415 miss); | |
1416 } | |
1417 | |
1418 if (lookup->IsField()) { | |
1419 // We found FIELD property in prototype chain of interceptor's holder. | |
1420 // Retrieve a field from field's holder. | |
1421 GenerateFastPropertyLoad(masm(), v0, holder_reg, | |
1422 Handle<JSObject>(lookup->holder()), | |
1423 lookup->GetFieldIndex()); | |
1424 __ Ret(); | |
1425 } else { | |
1426 // We found CALLBACKS property in prototype chain of interceptor's | |
1427 // holder. | |
1428 ASSERT(lookup->type() == CALLBACKS); | |
1429 Handle<ExecutableAccessorInfo> callback( | |
1430 ExecutableAccessorInfo::cast(lookup->GetCallbackObject())); | |
1431 ASSERT(callback->getter() != NULL); | |
1432 | |
1433 // Tail call to runtime. | |
1434 // Important invariant in CALLBACKS case: the code above must be | |
1435 // structured to never clobber |receiver| register. | |
1436 __ li(scratch2, callback); | |
1437 | |
1438 __ Push(receiver, holder_reg); | |
1439 __ lw(scratch3, | |
1440 FieldMemOperand(scratch2, ExecutableAccessorInfo::kDataOffset)); | |
1441 __ li(scratch1, Operand(ExternalReference::isolate_address())); | |
1442 __ Push(scratch3, scratch1, scratch2, name_reg); | |
1443 | |
1444 ExternalReference ref = | |
1445 ExternalReference(IC_Utility(IC::kLoadCallbackProperty), | |
1446 masm()->isolate()); | |
1447 __ TailCallExternalReference(ref, 6, 1); | |
1448 } | |
1449 } else { // !compile_followup_inline | 1394 } else { // !compile_followup_inline |
1450 // Call the runtime system to load the interceptor. | 1395 // Call the runtime system to load the interceptor. |
1451 // Check that the maps haven't changed. | 1396 // Check that the maps haven't changed. |
1452 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1397 PushInterceptorArguments(masm(), receiver(), holder_reg, |
1453 scratch1, scratch2, scratch3, | 1398 this->name(), interceptor_holder); |
1454 name, miss); | |
1455 PushInterceptorArguments(masm(), receiver, holder_reg, | |
1456 name_reg, interceptor_holder); | |
1457 | 1399 |
1458 ExternalReference ref = ExternalReference( | 1400 ExternalReference ref = ExternalReference( |
1459 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate()); | 1401 IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), masm()->isolate()); |
1460 __ TailCallExternalReference(ref, 6, 1); | 1402 __ TailCallExternalReference(ref, 6, 1); |
1461 } | 1403 } |
1462 } | 1404 } |
1463 | 1405 |
1464 | 1406 |
1465 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { | 1407 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { |
1466 if (kind_ == Code::KEYED_CALL_IC) { | 1408 if (kind_ == Code::KEYED_CALL_IC) { |
(...skipping 1431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2898 // Return the generated code. | 2840 // Return the generated code. |
2899 return GetCode(Code::NORMAL, name); | 2841 return GetCode(Code::NORMAL, name); |
2900 } | 2842 } |
2901 | 2843 |
2902 | 2844 |
2903 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( | 2845 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( |
2904 Handle<JSObject> object, | 2846 Handle<JSObject> object, |
2905 Handle<JSObject> last, | 2847 Handle<JSObject> last, |
2906 Handle<String> name, | 2848 Handle<String> name, |
2907 Handle<GlobalObject> global) { | 2849 Handle<GlobalObject> global) { |
2908 // ----------- S t a t e ------------- | 2850 Label success; |
2909 // -- a0 : receiver | |
2910 // -- ra : return address | |
2911 // ----------------------------------- | |
2912 Label miss; | |
2913 | 2851 |
2914 // Check that the receiver is not a smi. | 2852 NonexistentHandlerFrontend(object, last, name, &success, global); |
2915 __ JumpIfSmi(a0, &miss); | |
2916 | 2853 |
2917 Register scratch = a1; | 2854 __ bind(&success); |
2918 | |
2919 // Check the maps of the full prototype chain. | |
2920 Register result = | |
2921 CheckPrototypes(object, a0, last, a3, scratch, t0, name, &miss); | |
2922 | |
2923 // If the last object in the prototype chain is a global object, | |
2924 // check that the global property cell is empty. | |
2925 if (!global.is_null()) { | |
2926 GenerateCheckPropertyCell(masm(), global, name, scratch, &miss); | |
2927 } | |
2928 | |
2929 if (!last->HasFastProperties()) { | |
2930 __ lw(scratch, FieldMemOperand(result, HeapObject::kMapOffset)); | |
2931 __ lw(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset)); | |
2932 __ Branch(&miss, ne, scratch, Operand(isolate()->factory()->null_value())); | |
2933 } | |
2934 | |
2935 // Return undefined if maps of the full prototype chain is still the same. | 2855 // Return undefined if maps of the full prototype chain is still the same. |
2936 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); | 2856 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); |
2937 __ Ret(); | 2857 __ Ret(); |
2938 | 2858 |
2939 __ bind(&miss); | |
2940 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
2941 | |
2942 // Return the generated code. | 2859 // Return the generated code. |
2943 return GetCode(Code::NONEXISTENT, factory()->empty_string()); | 2860 return GetCode(Code::NONEXISTENT, factory()->empty_string()); |
2944 } | 2861 } |
2945 | 2862 |
2946 | 2863 |
2947 Register* LoadStubCompiler::registers() { | 2864 Register* LoadStubCompiler::registers() { |
2948 // receiver, name, scratch1, scratch2, scratch3, scratch4. | 2865 // receiver, name, scratch1, scratch2, scratch3, scratch4. |
2949 static Register registers[] = { a0, a2, a3, a1, t0, t1 }; | 2866 static Register registers[] = { a0, a2, a3, a1, t0, t1 }; |
2950 return registers; | 2867 return registers; |
2951 } | 2868 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2995 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2912 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2996 } | 2913 } |
2997 __ Ret(); | 2914 __ Ret(); |
2998 } | 2915 } |
2999 | 2916 |
3000 | 2917 |
3001 #undef __ | 2918 #undef __ |
3002 #define __ ACCESS_MASM(masm()) | 2919 #define __ ACCESS_MASM(masm()) |
3003 | 2920 |
3004 | 2921 |
3005 Handle<Code> LoadStubCompiler::CompileLoadViaGetter( | |
3006 Handle<JSObject> receiver, | |
3007 Handle<JSObject> holder, | |
3008 Handle<String> name, | |
3009 Handle<JSFunction> getter) { | |
3010 // ----------- S t a t e ------------- | |
3011 // -- a0 : receiver | |
3012 // -- a2 : name | |
3013 // -- ra : return address | |
3014 // ----------------------------------- | |
3015 Label miss; | |
3016 | |
3017 // Check that the maps haven't changed. | |
3018 __ JumpIfSmi(a0, &miss); | |
3019 CheckPrototypes(receiver, a0, holder, a3, t0, a1, name, &miss); | |
3020 | |
3021 GenerateLoadViaGetter(masm(), getter); | |
3022 | |
3023 __ bind(&miss); | |
3024 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
3025 | |
3026 // Return the generated code. | |
3027 return GetCode(Code::CALLBACKS, name); | |
3028 } | |
3029 | |
3030 | |
3031 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2922 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
3032 Handle<JSObject> object, | 2923 Handle<JSObject> object, |
3033 Handle<GlobalObject> holder, | 2924 Handle<GlobalObject> global, |
3034 Handle<JSGlobalPropertyCell> cell, | 2925 Handle<JSGlobalPropertyCell> cell, |
3035 Handle<String> name, | 2926 Handle<String> name, |
3036 bool is_dont_delete) { | 2927 bool is_dont_delete) { |
3037 // ----------- S t a t e ------------- | 2928 Label success, miss; |
3038 // -- a0 : receiver | |
3039 // -- a2 : name | |
3040 // -- ra : return address | |
3041 // ----------------------------------- | |
3042 Label miss; | |
3043 | 2929 |
3044 // Check that the map of the global has not changed. | 2930 HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global), |
3045 __ JumpIfSmi(a0, &miss); | 2931 name, &miss, PERFORM_INITIAL_CHECKS); |
3046 CheckPrototypes(object, a0, holder, a3, t0, a1, name, &miss); | |
3047 | 2932 |
3048 // Get the value from the cell. | 2933 // Get the value from the cell. |
3049 __ li(a3, Operand(cell)); | 2934 __ li(a3, Operand(cell)); |
3050 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset)); | 2935 __ lw(t0, FieldMemOperand(a3, JSGlobalPropertyCell::kValueOffset)); |
3051 | 2936 |
3052 // Check for deleted property if property can actually be deleted. | 2937 // Check for deleted property if property can actually be deleted. |
3053 if (!is_dont_delete) { | 2938 if (!is_dont_delete) { |
3054 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 2939 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
3055 __ Branch(&miss, eq, t0, Operand(at)); | 2940 __ Branch(&miss, eq, t0, Operand(at)); |
3056 } | 2941 } |
3057 | 2942 |
3058 __ mov(v0, t0); | 2943 HandlerFrontendFooter(&success, &miss); |
| 2944 __ bind(&success); |
| 2945 |
3059 Counters* counters = masm()->isolate()->counters(); | 2946 Counters* counters = masm()->isolate()->counters(); |
3060 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3); | 2947 __ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3); |
| 2948 __ mov(v0, t0); |
3061 __ Ret(); | 2949 __ Ret(); |
3062 | 2950 |
3063 __ bind(&miss); | |
3064 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, a1, a3); | |
3065 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
3066 | |
3067 // Return the generated code. | 2951 // Return the generated code. |
3068 return GetCode(Code::NORMAL, name); | 2952 return GetCode(Code::NORMAL, name); |
3069 } | 2953 } |
3070 | 2954 |
3071 | 2955 |
3072 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( | 2956 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( |
3073 Handle<Map> receiver_map) { | 2957 Handle<Map> receiver_map) { |
3074 // ----------- S t a t e ------------- | 2958 // ----------- S t a t e ------------- |
3075 // -- ra : return address | 2959 // -- ra : return address |
3076 // -- a0 : key | 2960 // -- a0 : key |
(...skipping 1151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4228 __ Jump(ic_slow, RelocInfo::CODE_TARGET); | 4112 __ Jump(ic_slow, RelocInfo::CODE_TARGET); |
4229 } | 4113 } |
4230 } | 4114 } |
4231 | 4115 |
4232 | 4116 |
4233 #undef __ | 4117 #undef __ |
4234 | 4118 |
4235 } } // namespace v8::internal | 4119 } } // namespace v8::internal |
4236 | 4120 |
4237 #endif // V8_TARGET_ARCH_MIPS | 4121 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |