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 __ b(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<AccessorInfo> 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 __ ldr(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 __ ldr(scratch2(), FieldMemOperand(pointer, kValueOffset)); |
| 1219 __ cmp(scratch2(), Operand(callback)); |
| 1220 __ b(ne, &miss); |
| 1221 } |
| 1222 |
| 1223 HandlerFrontendFooter(success, &miss); |
| 1224 return reg; |
| 1225 } |
| 1226 |
| 1227 |
| 1228 void BaseLoadStubCompiler::NonexistentHandlerFrontend( |
| 1229 Handle<JSObject> object, |
| 1230 Handle<JSObject> last, |
| 1231 Handle<String> name, |
| 1232 Label* success, |
| 1233 Handle<GlobalObject> global) { |
| 1234 Label miss; |
| 1235 |
| 1236 Register reg = HandlerFrontendHeader( |
| 1237 object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS); |
| 1238 |
| 1239 // If the last object in the prototype chain is a global object, |
| 1240 // check that the global property cell is empty. |
| 1241 if (!global.is_null()) { |
| 1242 GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss); |
| 1243 } |
| 1244 |
| 1245 if (!last->HasFastProperties()) { |
| 1246 __ ldr(scratch2(), FieldMemOperand(reg, HeapObject::kMapOffset)); |
| 1247 __ ldr(scratch2(), FieldMemOperand(scratch2(), Map::kPrototypeOffset)); |
| 1248 __ cmp(scratch2(), Operand(isolate()->factory()->null_value())); |
| 1249 __ b(ne, &miss); |
| 1250 } |
| 1251 |
| 1252 HandlerFrontendFooter(success, &miss); |
| 1253 } |
| 1254 |
| 1255 |
| 1256 void BaseLoadStubCompiler::GenerateLoadField(Register reg, |
| 1257 Handle<JSObject> holder, |
| 1258 PropertyIndex index) { |
1186 GenerateFastPropertyLoad(masm(), r0, reg, holder, index); | 1259 GenerateFastPropertyLoad(masm(), r0, reg, holder, index); |
1187 __ Ret(); | 1260 __ Ret(); |
1188 } | 1261 } |
1189 | 1262 |
1190 | 1263 |
1191 void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, | 1264 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); | |
1202 | |
1203 // Check that the maps haven't changed. | |
1204 CheckPrototypes( | |
1205 object, receiver, holder, scratch1, scratch2, scratch3, name, miss); | |
1206 | |
1207 // Return the constant value. | 1265 // Return the constant value. |
1208 __ LoadHeapObject(r0, value); | 1266 __ LoadHeapObject(r0, value); |
1209 __ Ret(); | 1267 __ Ret(); |
1210 } | 1268 } |
1211 | 1269 |
1212 | 1270 |
1213 void StubCompiler::GenerateDictionaryLoadCallback(Register receiver, | 1271 void BaseLoadStubCompiler::GenerateLoadCallback(Register reg, |
1214 Register name_reg, | 1272 Handle<AccessorInfo> callback) { |
1215 Register scratch1, | |
1216 Register scratch2, | |
1217 Register scratch3, | |
1218 Handle<AccessorInfo> callback, | |
1219 Handle<String> name, | |
1220 Label* miss) { | |
1221 ASSERT(!receiver.is(scratch1)); | |
1222 ASSERT(!receiver.is(scratch2)); | |
1223 ASSERT(!receiver.is(scratch3)); | |
1224 | |
1225 // Load the properties dictionary. | |
1226 Register dictionary = scratch1; | |
1227 __ ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | |
1228 | |
1229 // Probe the dictionary. | |
1230 Label probe_done; | |
1231 StringDictionaryLookupStub::GeneratePositiveLookup(masm(), | |
1232 miss, | |
1233 &probe_done, | |
1234 dictionary, | |
1235 name_reg, | |
1236 scratch2, | |
1237 scratch3); | |
1238 __ bind(&probe_done); | |
1239 | |
1240 // If probing finds an entry in the dictionary, scratch3 contains the | |
1241 // pointer into the dictionary. Check that the value is the callback. | |
1242 Register pointer = scratch3; | |
1243 const int kElementsStartOffset = StringDictionary::kHeaderSize + | |
1244 StringDictionary::kElementsStartIndex * kPointerSize; | |
1245 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
1246 __ ldr(scratch2, FieldMemOperand(pointer, kValueOffset)); | |
1247 __ cmp(scratch2, Operand(callback)); | |
1248 __ b(ne, miss); | |
1249 } | |
1250 | |
1251 | |
1252 void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, | |
1253 Handle<JSObject> holder, | |
1254 Register receiver, | |
1255 Register name_reg, | |
1256 Register scratch1, | |
1257 Register scratch2, | |
1258 Register scratch3, | |
1259 Register scratch4, | |
1260 Handle<AccessorInfo> callback, | |
1261 Handle<String> name, | |
1262 Label* miss) { | |
1263 // Check that the receiver isn't a smi. | |
1264 __ JumpIfSmi(receiver, miss); | |
1265 | |
1266 // Check that the maps haven't changed. | |
1267 Register reg = CheckPrototypes(object, receiver, holder, scratch1, | |
1268 scratch2, scratch3, name, miss); | |
1269 | |
1270 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | |
1271 GenerateDictionaryLoadCallback( | |
1272 reg, name_reg, scratch2, scratch3, scratch4, callback, name, miss); | |
1273 } | |
1274 | |
1275 // 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 |
1276 // 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. |
1277 __ push(receiver); | 1275 __ push(receiver()); |
1278 __ mov(scratch2, sp); // scratch2 = AccessorInfo::args_ | 1276 __ mov(scratch2(), sp); // scratch2 = AccessorInfo::args_ |
1279 if (heap()->InNewSpace(callback->data())) { | 1277 if (heap()->InNewSpace(callback->data())) { |
1280 __ Move(scratch3, callback); | 1278 __ Move(scratch3(), callback); |
1281 __ ldr(scratch3, FieldMemOperand(scratch3, AccessorInfo::kDataOffset)); | 1279 __ ldr(scratch3(), FieldMemOperand(scratch3(), AccessorInfo::kDataOffset)); |
1282 } else { | 1280 } else { |
1283 __ Move(scratch3, Handle<Object>(callback->data())); | 1281 __ Move(scratch3(), Handle<Object>(callback->data())); |
1284 } | 1282 } |
1285 __ Push(reg, scratch3); | 1283 __ Push(reg, scratch3()); |
1286 __ mov(scratch3, Operand(ExternalReference::isolate_address())); | 1284 __ mov(scratch3(), Operand(ExternalReference::isolate_address())); |
1287 __ Push(scratch3, name_reg); | 1285 __ Push(scratch3(), name()); |
1288 __ mov(r0, sp); // r0 = Handle<String> | 1286 __ mov(r0, sp); // r0 = Handle<String> |
1289 | 1287 |
1290 const int kApiStackSpace = 1; | 1288 const int kApiStackSpace = 1; |
1291 FrameScope frame_scope(masm(), StackFrame::MANUAL); | 1289 FrameScope frame_scope(masm(), StackFrame::MANUAL); |
1292 __ EnterExitFrame(false, kApiStackSpace); | 1290 __ EnterExitFrame(false, kApiStackSpace); |
1293 | 1291 |
1294 // Create AccessorInfo instance on the stack above the exit frame with | 1292 // Create AccessorInfo instance on the stack above the exit frame with |
1295 // scratch2 (internal::Object** args_) as the data. | 1293 // scratch2 (internal::Object** args_) as the data. |
1296 __ str(scratch2, MemOperand(sp, 1 * kPointerSize)); | 1294 __ str(scratch2(), MemOperand(sp, 1 * kPointerSize)); |
1297 __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& | 1295 __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& |
1298 | 1296 |
1299 const int kStackUnwindSpace = 5; | 1297 const int kStackUnwindSpace = 5; |
1300 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1298 Address getter_address = v8::ToCData<Address>(callback->getter()); |
1301 ApiFunction fun(getter_address); | 1299 ApiFunction fun(getter_address); |
1302 ExternalReference ref = | 1300 ExternalReference ref = |
1303 ExternalReference(&fun, | 1301 ExternalReference(&fun, |
1304 ExternalReference::DIRECT_GETTER_CALL, | 1302 ExternalReference::DIRECT_GETTER_CALL, |
1305 masm()->isolate()); | 1303 masm()->isolate()); |
1306 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace); | 1304 __ CallApiFunctionAndReturn(ref, kStackUnwindSpace); |
1307 } | 1305 } |
1308 | 1306 |
1309 | 1307 |
1310 void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, | 1308 void BaseLoadStubCompiler::GenerateLoadInterceptor( |
1311 Handle<JSObject> interceptor_holder, | 1309 Register holder_reg, |
1312 LookupResult* lookup, | 1310 Handle<JSObject> object, |
1313 Register receiver, | 1311 Handle<JSObject> interceptor_holder, |
1314 Register name_reg, | 1312 LookupResult* lookup, |
1315 Register scratch1, | 1313 Handle<String> name) { |
1316 Register scratch2, | |
1317 Register scratch3, | |
1318 Handle<String> name, | |
1319 Label* miss) { | |
1320 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1314 ASSERT(interceptor_holder->HasNamedInterceptor()); |
1321 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 1315 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
1322 | 1316 |
1323 // Check that the receiver isn't a smi. | |
1324 __ JumpIfSmi(receiver, miss); | |
1325 | |
1326 // So far the most popular follow ups for interceptor loads are FIELD | 1317 // So far the most popular follow ups for interceptor loads are FIELD |
1327 // and CALLBACKS, so inline only them, other cases may be added | 1318 // and CALLBACKS, so inline only them, other cases may be added |
1328 // later. | 1319 // later. |
1329 bool compile_followup_inline = false; | 1320 bool compile_followup_inline = false; |
1330 if (lookup->IsFound() && lookup->IsCacheable()) { | 1321 if (lookup->IsFound() && lookup->IsCacheable()) { |
1331 if (lookup->IsField()) { | 1322 if (lookup->IsField()) { |
1332 compile_followup_inline = true; | 1323 compile_followup_inline = true; |
1333 } else if (lookup->type() == CALLBACKS && | 1324 } else if (lookup->type() == CALLBACKS && |
1334 lookup->GetCallbackObject()->IsAccessorInfo()) { | 1325 lookup->GetCallbackObject()->IsAccessorInfo()) { |
1335 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); | 1326 AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
1336 compile_followup_inline = callback->getter() != NULL && | 1327 compile_followup_inline = callback->getter() != NULL && |
1337 callback->IsCompatibleReceiver(*object); | 1328 callback->IsCompatibleReceiver(*object); |
1338 } | 1329 } |
1339 } | 1330 } |
1340 | 1331 |
1341 if (compile_followup_inline) { | 1332 if (compile_followup_inline) { |
1342 // Compile the interceptor call, followed by inline code to load the | 1333 // Compile the interceptor call, followed by inline code to load the |
1343 // property from further up the prototype chain if the call fails. | 1334 // property from further up the prototype chain if the call fails. |
1344 // Check that the maps haven't changed. | 1335 // Check that the maps haven't changed. |
1345 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1336 ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
1346 scratch1, scratch2, scratch3, | |
1347 name, miss); | |
1348 ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); | |
1349 | 1337 |
1350 // Preserve the receiver register explicitly whenever it is different from | 1338 // Preserve the receiver register explicitly whenever it is different from |
1351 // the holder and it is needed should the interceptor return without any | 1339 // the holder and it is needed should the interceptor return without any |
1352 // result. The CALLBACKS case needs the receiver to be passed into C++ code, | 1340 // result. The CALLBACKS case needs the receiver to be passed into C++ code, |
1353 // the FIELD case might cause a miss during the prototype check. | 1341 // the FIELD case might cause a miss during the prototype check. |
1354 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); | 1342 bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); |
1355 bool must_preserve_receiver_reg = !receiver.is(holder_reg) && | 1343 bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
1356 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); | 1344 (lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
1357 | 1345 |
1358 // Save necessary data before invoking an interceptor. | 1346 // Save necessary data before invoking an interceptor. |
1359 // Requires a frame to make GC aware of pushed pointers. | 1347 // Requires a frame to make GC aware of pushed pointers. |
1360 { | 1348 { |
1361 FrameScope frame_scope(masm(), StackFrame::INTERNAL); | 1349 FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
1362 if (must_preserve_receiver_reg) { | 1350 if (must_preserve_receiver_reg) { |
1363 __ Push(receiver, holder_reg, name_reg); | 1351 __ Push(receiver(), holder_reg, this->name()); |
1364 } else { | 1352 } else { |
1365 __ Push(holder_reg, name_reg); | 1353 __ Push(holder_reg, this->name()); |
1366 } | 1354 } |
1367 // Invoke an interceptor. Note: map checks from receiver to | 1355 // Invoke an interceptor. Note: map checks from receiver to |
1368 // interceptor's holder has been compiled before (see a caller | 1356 // interceptor's holder has been compiled before (see a caller |
1369 // of this method.) | 1357 // of this method.) |
1370 CompileCallLoadPropertyWithInterceptor(masm(), | 1358 CompileCallLoadPropertyWithInterceptor(masm(), |
1371 receiver, | 1359 receiver(), |
1372 holder_reg, | 1360 holder_reg, |
1373 name_reg, | 1361 this->name(), |
1374 interceptor_holder); | 1362 interceptor_holder); |
1375 // Check if interceptor provided a value for property. If it's | 1363 // Check if interceptor provided a value for property. If it's |
1376 // the case, return immediately. | 1364 // the case, return immediately. |
1377 Label interceptor_failed; | 1365 Label interceptor_failed; |
1378 __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); | 1366 __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex); |
1379 __ cmp(r0, scratch1); | 1367 __ cmp(r0, scratch1()); |
1380 __ b(eq, &interceptor_failed); | 1368 __ b(eq, &interceptor_failed); |
1381 frame_scope.GenerateLeaveFrame(); | 1369 frame_scope.GenerateLeaveFrame(); |
1382 __ Ret(); | 1370 __ Ret(); |
1383 | 1371 |
1384 __ bind(&interceptor_failed); | 1372 __ bind(&interceptor_failed); |
1385 __ pop(name_reg); | 1373 __ pop(this->name()); |
1386 __ pop(holder_reg); | 1374 __ pop(holder_reg); |
1387 if (must_preserve_receiver_reg) { | 1375 if (must_preserve_receiver_reg) { |
1388 __ pop(receiver); | 1376 __ pop(receiver()); |
1389 } | 1377 } |
1390 // Leave the internal frame. | 1378 // Leave the internal frame. |
1391 } | 1379 } |
1392 // Check that the maps from interceptor's holder to lookup's holder | |
1393 // haven't changed. And load lookup's holder into |holder| register. | |
1394 if (must_perfrom_prototype_check) { | |
1395 holder_reg = CheckPrototypes(interceptor_holder, | |
1396 holder_reg, | |
1397 Handle<JSObject>(lookup->holder()), | |
1398 scratch1, | |
1399 scratch2, | |
1400 scratch3, | |
1401 name, | |
1402 miss); | |
1403 } | |
1404 | 1380 |
1405 if (lookup->IsField()) { | 1381 GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup); |
1406 // We found FIELD property in prototype chain of interceptor's holder. | |
1407 // Retrieve a field from field's holder. | |
1408 GenerateFastPropertyLoad(masm(), r0, holder_reg, | |
1409 Handle<JSObject>(lookup->holder()), | |
1410 lookup->GetFieldIndex()); | |
1411 __ Ret(); | |
1412 } else { | |
1413 // We found CALLBACKS property in prototype chain of interceptor's | |
1414 // holder. | |
1415 ASSERT(lookup->type() == CALLBACKS); | |
1416 Handle<AccessorInfo> callback( | |
1417 AccessorInfo::cast(lookup->GetCallbackObject())); | |
1418 ASSERT(callback->getter() != NULL); | |
1419 | |
1420 // Tail call to runtime. | |
1421 // Important invariant in CALLBACKS case: the code above must be | |
1422 // structured to never clobber |receiver| register. | |
1423 __ Move(scratch2, callback); | |
1424 // holder_reg is either receiver or scratch1. | |
1425 if (!receiver.is(holder_reg)) { | |
1426 ASSERT(scratch1.is(holder_reg)); | |
1427 __ Push(receiver, holder_reg); | |
1428 } else { | |
1429 __ push(receiver); | |
1430 __ push(holder_reg); | |
1431 } | |
1432 __ ldr(scratch3, | |
1433 FieldMemOperand(scratch2, AccessorInfo::kDataOffset)); | |
1434 __ mov(scratch1, Operand(ExternalReference::isolate_address())); | |
1435 __ Push(scratch3, scratch1, scratch2, name_reg); | |
1436 | |
1437 ExternalReference ref = | |
1438 ExternalReference(IC_Utility(IC::kLoadCallbackProperty), | |
1439 masm()->isolate()); | |
1440 __ TailCallExternalReference(ref, 6, 1); | |
1441 } | |
1442 } else { // !compile_followup_inline | 1382 } else { // !compile_followup_inline |
1443 // Call the runtime system to load the interceptor. | 1383 // Call the runtime system to load the interceptor. |
1444 // Check that the maps haven't changed. | 1384 // Check that the maps haven't changed. |
1445 Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, | 1385 PushInterceptorArguments(masm(), receiver(), holder_reg, |
1446 scratch1, scratch2, scratch3, | 1386 this->name(), interceptor_holder); |
1447 name, miss); | |
1448 PushInterceptorArguments(masm(), receiver, holder_reg, | |
1449 name_reg, interceptor_holder); | |
1450 | 1387 |
1451 ExternalReference ref = | 1388 ExternalReference ref = |
1452 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1389 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
1453 masm()->isolate()); | 1390 masm()->isolate()); |
1454 __ TailCallExternalReference(ref, 6, 1); | 1391 __ TailCallExternalReference(ref, 6, 1); |
1455 } | 1392 } |
1456 } | 1393 } |
1457 | 1394 |
1458 | 1395 |
1459 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { | 1396 void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { |
(...skipping 1435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2895 // Return the generated code. | 2832 // Return the generated code. |
2896 return GetCode(Code::NORMAL, name); | 2833 return GetCode(Code::NORMAL, name); |
2897 } | 2834 } |
2898 | 2835 |
2899 | 2836 |
2900 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( | 2837 Handle<Code> LoadStubCompiler::CompileLoadNonexistent( |
2901 Handle<JSObject> object, | 2838 Handle<JSObject> object, |
2902 Handle<JSObject> last, | 2839 Handle<JSObject> last, |
2903 Handle<String> name, | 2840 Handle<String> name, |
2904 Handle<GlobalObject> global) { | 2841 Handle<GlobalObject> global) { |
2905 // ----------- S t a t e ------------- | 2842 Label success; |
2906 // -- r0 : receiver | |
2907 // -- lr : return address | |
2908 // ----------------------------------- | |
2909 Label miss; | |
2910 | 2843 |
2911 // Check that receiver is not a smi. | 2844 NonexistentHandlerFrontend(object, last, name, &success, global); |
2912 __ JumpIfSmi(r0, &miss); | |
2913 | 2845 |
2914 | 2846 __ bind(&success); |
2915 Register scratch = r1; | |
2916 | |
2917 // Check the maps of the full prototype chain. | |
2918 Register result = | |
2919 CheckPrototypes(object, r0, last, r3, scratch, r4, name, &miss); | |
2920 | |
2921 // If the last object in the prototype chain is a global object, | |
2922 // check that the global property cell is empty. | |
2923 if (!global.is_null()) { | |
2924 GenerateCheckPropertyCell(masm(), global, name, scratch, &miss); | |
2925 } | |
2926 | |
2927 if (!last->HasFastProperties()) { | |
2928 __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset)); | |
2929 __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset)); | |
2930 __ cmp(scratch, Operand(isolate()->factory()->null_value())); | |
2931 __ b(ne, &miss); | |
2932 } | |
2933 | |
2934 // Return undefined if maps of the full prototype chain are still the | 2847 // Return undefined if maps of the full prototype chain are still the |
2935 // same and no global property with this name contains a value. | 2848 // same and no global property with this name contains a value. |
2936 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 2849 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
2937 __ Ret(); | 2850 __ Ret(); |
2938 | 2851 |
2939 __ bind(&miss); | |
2940 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
2941 | |
2942 // Return the generated code. | 2852 // Return the generated code. |
2943 return GetCode(Code::NONEXISTENT, factory()->empty_string()); | 2853 return GetCode(Code::NONEXISTENT, factory()->empty_string()); |
2944 } | 2854 } |
2945 | 2855 |
2946 | 2856 |
2947 Register* LoadStubCompiler::registers() { | 2857 Register* LoadStubCompiler::registers() { |
2948 // receiver, name, scratch1, scratch2, scratch3, scratch4. | 2858 // receiver, name, scratch1, scratch2, scratch3, scratch4. |
2949 static Register registers[] = { r0, r2, r3, r1, r4, r5 }; | 2859 static Register registers[] = { r0, r2, r3, r1, r4, r5 }; |
2950 return registers; | 2860 return registers; |
2951 } | 2861 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2996 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2906 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
2997 } | 2907 } |
2998 __ Ret(); | 2908 __ Ret(); |
2999 } | 2909 } |
3000 | 2910 |
3001 | 2911 |
3002 #undef __ | 2912 #undef __ |
3003 #define __ ACCESS_MASM(masm()) | 2913 #define __ ACCESS_MASM(masm()) |
3004 | 2914 |
3005 | 2915 |
3006 Handle<Code> LoadStubCompiler::CompileLoadViaGetter( | |
3007 Handle<JSObject> receiver, | |
3008 Handle<JSObject> holder, | |
3009 Handle<String> name, | |
3010 Handle<JSFunction> getter) { | |
3011 // ----------- S t a t e ------------- | |
3012 // -- r0 : receiver | |
3013 // -- r2 : name | |
3014 // -- lr : return address | |
3015 // ----------------------------------- | |
3016 Label miss; | |
3017 | |
3018 // Check that the maps haven't changed. | |
3019 __ JumpIfSmi(r0, &miss); | |
3020 CheckPrototypes(receiver, r0, holder, r3, r4, r1, name, &miss); | |
3021 | |
3022 GenerateLoadViaGetter(masm(), getter); | |
3023 | |
3024 __ bind(&miss); | |
3025 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
3026 | |
3027 // Return the generated code. | |
3028 return GetCode(Code::CALLBACKS, name); | |
3029 } | |
3030 | |
3031 | |
3032 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2916 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
3033 Handle<JSObject> object, | 2917 Handle<JSObject> object, |
3034 Handle<GlobalObject> holder, | 2918 Handle<GlobalObject> global, |
3035 Handle<JSGlobalPropertyCell> cell, | 2919 Handle<JSGlobalPropertyCell> cell, |
3036 Handle<String> name, | 2920 Handle<String> name, |
3037 bool is_dont_delete) { | 2921 bool is_dont_delete) { |
3038 // ----------- S t a t e ------------- | 2922 Label success, miss; |
3039 // -- r0 : receiver | |
3040 // -- r2 : name | |
3041 // -- lr : return address | |
3042 // ----------------------------------- | |
3043 Label miss; | |
3044 | 2923 |
3045 // Check that the map of the global has not changed. | 2924 HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global), |
3046 __ JumpIfSmi(r0, &miss); | 2925 name, &miss, PERFORM_INITIAL_CHECKS); |
3047 CheckPrototypes(object, r0, holder, r3, r4, r1, name, &miss); | |
3048 | 2926 |
3049 // Get the value from the cell. | 2927 // Get the value from the cell. |
3050 __ mov(r3, Operand(cell)); | 2928 __ mov(r3, Operand(cell)); |
3051 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); | 2929 __ ldr(r4, FieldMemOperand(r3, JSGlobalPropertyCell::kValueOffset)); |
3052 | 2930 |
3053 // Check for deleted property if property can actually be deleted. | 2931 // Check for deleted property if property can actually be deleted. |
3054 if (!is_dont_delete) { | 2932 if (!is_dont_delete) { |
3055 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2933 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
3056 __ cmp(r4, ip); | 2934 __ cmp(r4, ip); |
3057 __ b(eq, &miss); | 2935 __ b(eq, &miss); |
3058 } | 2936 } |
3059 | 2937 |
3060 __ mov(r0, r4); | 2938 HandlerFrontendFooter(&success, &miss); |
| 2939 __ bind(&success); |
| 2940 |
3061 Counters* counters = masm()->isolate()->counters(); | 2941 Counters* counters = masm()->isolate()->counters(); |
3062 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); | 2942 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); |
| 2943 __ mov(r0, r4); |
3063 __ Ret(); | 2944 __ Ret(); |
3064 | 2945 |
3065 __ bind(&miss); | |
3066 __ IncrementCounter(counters->named_load_global_stub_miss(), 1, r1, r3); | |
3067 GenerateLoadMiss(masm(), Code::LOAD_IC); | |
3068 | |
3069 // Return the generated code. | 2946 // Return the generated code. |
3070 return GetCode(Code::NORMAL, name); | 2947 return GetCode(Code::NORMAL, name); |
3071 } | 2948 } |
3072 | 2949 |
3073 | 2950 |
3074 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( | 2951 Handle<Code> KeyedLoadStubCompiler::CompileLoadElement( |
3075 Handle<Map> receiver_map) { | 2952 Handle<Map> receiver_map) { |
3076 // ----------- S t a t e ------------- | 2953 // ----------- S t a t e ------------- |
3077 // -- lr : return address | 2954 // -- lr : return address |
3078 // -- r0 : key | 2955 // -- r0 : key |
(...skipping 1089 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4168 __ Jump(ic_slow, RelocInfo::CODE_TARGET); | 4045 __ Jump(ic_slow, RelocInfo::CODE_TARGET); |
4169 } | 4046 } |
4170 } | 4047 } |
4171 | 4048 |
4172 | 4049 |
4173 #undef __ | 4050 #undef __ |
4174 | 4051 |
4175 } } // namespace v8::internal | 4052 } } // namespace v8::internal |
4176 | 4053 |
4177 #endif // V8_TARGET_ARCH_ARM | 4054 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |