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