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