| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 UNREACHABLE(); | 56 UNREACHABLE(); |
| 57 return 0; | 57 return 0; |
| 58 } | 58 } |
| 59 | 59 |
| 60 void IC::TraceIC(const char* type, | 60 void IC::TraceIC(const char* type, |
| 61 Handle<String> name, | 61 Handle<String> name, |
| 62 State old_state, | 62 State old_state, |
| 63 Code* new_target, | 63 Code* new_target, |
| 64 const char* extra_info) { | 64 const char* extra_info) { |
| 65 if (FLAG_trace_ic) { | 65 if (FLAG_trace_ic) { |
| 66 State new_state = StateFrom(new_target, Heap::undefined_value()); | 66 State new_state = StateFrom(new_target, |
| 67 Heap::undefined_value(), |
| 68 Heap::undefined_value()); |
| 67 PrintF("[%s (%c->%c)%s", type, | 69 PrintF("[%s (%c->%c)%s", type, |
| 68 TransitionMarkFromState(old_state), | 70 TransitionMarkFromState(old_state), |
| 69 TransitionMarkFromState(new_state), | 71 TransitionMarkFromState(new_state), |
| 70 extra_info); | 72 extra_info); |
| 71 name->Print(); | 73 name->Print(); |
| 72 PrintF("]\n"); | 74 PrintF("]\n"); |
| 73 } | 75 } |
| 74 } | 76 } |
| 75 #endif | 77 #endif |
| 76 | 78 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 Address addr = pc() - Assembler::kCallTargetAddressOffset; | 127 Address addr = pc() - Assembler::kCallTargetAddressOffset; |
| 126 // Return the address in the original code. This is the place where | 128 // Return the address in the original code. This is the place where |
| 127 // the call which has been overwritten by the DebugBreakXXX resides | 129 // the call which has been overwritten by the DebugBreakXXX resides |
| 128 // and the place where the inline cache system should look. | 130 // and the place where the inline cache system should look. |
| 129 intptr_t delta = | 131 intptr_t delta = |
| 130 original_code->instruction_start() - code->instruction_start(); | 132 original_code->instruction_start() - code->instruction_start(); |
| 131 return addr + delta; | 133 return addr + delta; |
| 132 } | 134 } |
| 133 #endif | 135 #endif |
| 134 | 136 |
| 135 IC::State IC::StateFrom(Code* target, Object* receiver) { | 137 IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
| 136 IC::State state = target->ic_state(); | 138 IC::State state = target->ic_state(); |
| 137 | 139 |
| 138 if (state != MONOMORPHIC) return state; | 140 if (state != MONOMORPHIC) return state; |
| 139 if (receiver->IsUndefined() || receiver->IsNull()) return state; | 141 if (receiver->IsUndefined() || receiver->IsNull()) return state; |
| 140 | 142 |
| 141 Map* map = GetCodeCacheMapForObject(receiver); | 143 Map* map = GetCodeCacheMapForObject(receiver); |
| 142 | 144 |
| 143 // Decide whether the inline cache failed because of changes to the | 145 // Decide whether the inline cache failed because of changes to the |
| 144 // receiver itself or changes to one of its prototypes. | 146 // receiver itself or changes to one of its prototypes. |
| 145 // | 147 // |
| 146 // If there are changes to the receiver itself, the map of the | 148 // If there are changes to the receiver itself, the map of the |
| 147 // receiver will have changed and the current target will not be in | 149 // receiver will have changed and the current target will not be in |
| 148 // the receiver map's code cache. Therefore, if the current target | 150 // the receiver map's code cache. Therefore, if the current target |
| 149 // is in the receiver map's code cache, the inline cache failed due | 151 // is in the receiver map's code cache, the inline cache failed due |
| 150 // to prototype check failure. | 152 // to prototype check failure. |
| 151 int index = map->IndexInCodeCache(target); | 153 int index = map->IndexInCodeCache(String::cast(name), target); |
| 152 if (index >= 0) { | 154 if (index >= 0) { |
| 153 // For keyed load/store, the most likely cause of cache failure is | 155 // For keyed load/store, the most likely cause of cache failure is |
| 154 // that the key has changed. We do not distinguish between | 156 // that the key has changed. We do not distinguish between |
| 155 // prototype and non-prototype failures for keyed access. | 157 // prototype and non-prototype failures for keyed access. |
| 156 Code::Kind kind = target->kind(); | 158 Code::Kind kind = target->kind(); |
| 157 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { | 159 if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { |
| 158 return MONOMORPHIC; | 160 return MONOMORPHIC; |
| 159 } | 161 } |
| 160 | 162 |
| 161 // Remove the target from the code cache to avoid hitting the same | 163 // Remove the target from the code cache to avoid hitting the same |
| 162 // invalid stub again. | 164 // invalid stub again. |
| 163 map->RemoveFromCodeCache(index); | 165 map->RemoveFromCodeCache(String::cast(name), target, index); |
| 164 | 166 |
| 165 return MONOMORPHIC_PROTOTYPE_FAILURE; | 167 return MONOMORPHIC_PROTOTYPE_FAILURE; |
| 166 } | 168 } |
| 167 | 169 |
| 168 // The builtins object is special. It only changes when JavaScript | 170 // The builtins object is special. It only changes when JavaScript |
| 169 // builtins are loaded lazily. It is important to keep inline | 171 // builtins are loaded lazily. It is important to keep inline |
| 170 // caches for the builtins object monomorphic. Therefore, if we get | 172 // caches for the builtins object monomorphic. Therefore, if we get |
| 171 // an inline cache miss for the builtins object after lazily loading | 173 // an inline cache miss for the builtins object after lazily loading |
| 172 // JavaScript builtins, we return uninitialized as the state to | 174 // JavaScript builtins, we return uninitialized as the state to |
| 173 // force the inline cache back to monomorphic state. | 175 // force the inline cache back to monomorphic state. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 | 217 |
| 216 // Don't clear debug break inline cache as it will remove the break point. | 218 // Don't clear debug break inline cache as it will remove the break point. |
| 217 if (target->ic_state() == DEBUG_BREAK) return; | 219 if (target->ic_state() == DEBUG_BREAK) return; |
| 218 | 220 |
| 219 switch (target->kind()) { | 221 switch (target->kind()) { |
| 220 case Code::LOAD_IC: return LoadIC::Clear(address, target); | 222 case Code::LOAD_IC: return LoadIC::Clear(address, target); |
| 221 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); | 223 case Code::KEYED_LOAD_IC: return KeyedLoadIC::Clear(address, target); |
| 222 case Code::STORE_IC: return StoreIC::Clear(address, target); | 224 case Code::STORE_IC: return StoreIC::Clear(address, target); |
| 223 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); | 225 case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); |
| 224 case Code::CALL_IC: return CallIC::Clear(address, target); | 226 case Code::CALL_IC: return CallIC::Clear(address, target); |
| 227 case Code::BINARY_OP_IC: return BinaryOpIC::Clear(address, target); |
| 225 default: UNREACHABLE(); | 228 default: UNREACHABLE(); |
| 226 } | 229 } |
| 227 } | 230 } |
| 228 | 231 |
| 229 | 232 |
| 230 void CallIC::Clear(Address address, Code* target) { | 233 void CallIC::Clear(Address address, Code* target) { |
| 231 State state = target->ic_state(); | 234 State state = target->ic_state(); |
| 232 InLoopFlag in_loop = target->ic_in_loop(); | 235 InLoopFlag in_loop = target->ic_in_loop(); |
| 233 if (state == UNINITIALIZED) return; | 236 if (state == UNINITIALIZED) return; |
| 234 Code* code = | 237 Code* code = |
| (...skipping 1048 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1283 | 1286 |
| 1284 // ---------------------------------------------------------------------------- | 1287 // ---------------------------------------------------------------------------- |
| 1285 // Static IC stub generators. | 1288 // Static IC stub generators. |
| 1286 // | 1289 // |
| 1287 | 1290 |
| 1288 // Used from ic_<arch>.cc. | 1291 // Used from ic_<arch>.cc. |
| 1289 Object* CallIC_Miss(Arguments args) { | 1292 Object* CallIC_Miss(Arguments args) { |
| 1290 NoHandleAllocation na; | 1293 NoHandleAllocation na; |
| 1291 ASSERT(args.length() == 2); | 1294 ASSERT(args.length() == 2); |
| 1292 CallIC ic; | 1295 CallIC ic; |
| 1293 IC::State state = IC::StateFrom(ic.target(), args[0]); | 1296 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1294 Object* result = | 1297 Object* result = |
| 1295 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); | 1298 ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); |
| 1296 | 1299 |
| 1297 // The first time the inline cache is updated may be the first time the | 1300 // The first time the inline cache is updated may be the first time the |
| 1298 // function it references gets called. If the function was lazily compiled | 1301 // function it references gets called. If the function was lazily compiled |
| 1299 // then the first call will trigger a compilation. We check for this case | 1302 // then the first call will trigger a compilation. We check for this case |
| 1300 // and we do the compilation immediately, instead of waiting for the stub | 1303 // and we do the compilation immediately, instead of waiting for the stub |
| 1301 // currently attached to the JSFunction object to trigger compilation. We | 1304 // currently attached to the JSFunction object to trigger compilation. We |
| 1302 // do this in the case where we know that the inline cache is inside a loop, | 1305 // do this in the case where we know that the inline cache is inside a loop, |
| 1303 // because then we know that we want to optimize the function. | 1306 // because then we know that we want to optimize the function. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1316 } | 1319 } |
| 1317 return *function; | 1320 return *function; |
| 1318 } | 1321 } |
| 1319 | 1322 |
| 1320 | 1323 |
| 1321 // Used from ic_<arch>.cc. | 1324 // Used from ic_<arch>.cc. |
| 1322 Object* LoadIC_Miss(Arguments args) { | 1325 Object* LoadIC_Miss(Arguments args) { |
| 1323 NoHandleAllocation na; | 1326 NoHandleAllocation na; |
| 1324 ASSERT(args.length() == 2); | 1327 ASSERT(args.length() == 2); |
| 1325 LoadIC ic; | 1328 LoadIC ic; |
| 1326 IC::State state = IC::StateFrom(ic.target(), args[0]); | 1329 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1327 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); | 1330 return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
| 1328 } | 1331 } |
| 1329 | 1332 |
| 1330 | 1333 |
| 1331 // Used from ic_<arch>.cc | 1334 // Used from ic_<arch>.cc |
| 1332 Object* KeyedLoadIC_Miss(Arguments args) { | 1335 Object* KeyedLoadIC_Miss(Arguments args) { |
| 1333 NoHandleAllocation na; | 1336 NoHandleAllocation na; |
| 1334 ASSERT(args.length() == 2); | 1337 ASSERT(args.length() == 2); |
| 1335 KeyedLoadIC ic; | 1338 KeyedLoadIC ic; |
| 1336 IC::State state = IC::StateFrom(ic.target(), args[0]); | 1339 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1337 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); | 1340 return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); |
| 1338 } | 1341 } |
| 1339 | 1342 |
| 1340 | 1343 |
| 1341 // Used from ic_<arch>.cc. | 1344 // Used from ic_<arch>.cc. |
| 1342 Object* StoreIC_Miss(Arguments args) { | 1345 Object* StoreIC_Miss(Arguments args) { |
| 1343 NoHandleAllocation na; | 1346 NoHandleAllocation na; |
| 1344 ASSERT(args.length() == 3); | 1347 ASSERT(args.length() == 3); |
| 1345 StoreIC ic; | 1348 StoreIC ic; |
| 1346 IC::State state = IC::StateFrom(ic.target(), args[0]); | 1349 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1347 return ic.Store(state, args.at<Object>(0), args.at<String>(1), | 1350 return ic.Store(state, args.at<Object>(0), args.at<String>(1), |
| 1348 args.at<Object>(2)); | 1351 args.at<Object>(2)); |
| 1349 } | 1352 } |
| 1350 | 1353 |
| 1351 | 1354 |
| 1352 Object* StoreIC_ArrayLength(Arguments args) { | 1355 Object* StoreIC_ArrayLength(Arguments args) { |
| 1353 NoHandleAllocation nha; | 1356 NoHandleAllocation nha; |
| 1354 | 1357 |
| 1355 ASSERT(args.length() == 2); | 1358 ASSERT(args.length() == 2); |
| 1356 JSObject* receiver = JSObject::cast(args[0]); | 1359 JSObject* receiver = JSObject::cast(args[0]); |
| 1357 Object* len = args[1]; | 1360 Object* len = args[1]; |
| 1358 | 1361 |
| 1359 return receiver->SetElementsLength(len); | 1362 Object* result = receiver->SetElementsLength(len); |
| 1363 if (result->IsFailure()) return result; |
| 1364 return len; |
| 1360 } | 1365 } |
| 1361 | 1366 |
| 1362 | 1367 |
| 1363 // Extend storage is called in a store inline cache when | 1368 // Extend storage is called in a store inline cache when |
| 1364 // it is necessary to extend the properties array of a | 1369 // it is necessary to extend the properties array of a |
| 1365 // JSObject. | 1370 // JSObject. |
| 1366 Object* SharedStoreIC_ExtendStorage(Arguments args) { | 1371 Object* SharedStoreIC_ExtendStorage(Arguments args) { |
| 1367 NoHandleAllocation na; | 1372 NoHandleAllocation na; |
| 1368 ASSERT(args.length() == 3); | 1373 ASSERT(args.length() == 3); |
| 1369 | 1374 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1392 // Return the stored value. | 1397 // Return the stored value. |
| 1393 return value; | 1398 return value; |
| 1394 } | 1399 } |
| 1395 | 1400 |
| 1396 | 1401 |
| 1397 // Used from ic_<arch>.cc. | 1402 // Used from ic_<arch>.cc. |
| 1398 Object* KeyedStoreIC_Miss(Arguments args) { | 1403 Object* KeyedStoreIC_Miss(Arguments args) { |
| 1399 NoHandleAllocation na; | 1404 NoHandleAllocation na; |
| 1400 ASSERT(args.length() == 3); | 1405 ASSERT(args.length() == 3); |
| 1401 KeyedStoreIC ic; | 1406 KeyedStoreIC ic; |
| 1402 IC::State state = IC::StateFrom(ic.target(), args[0]); | 1407 IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
| 1403 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), | 1408 return ic.Store(state, args.at<Object>(0), args.at<Object>(1), |
| 1404 args.at<Object>(2)); | 1409 args.at<Object>(2)); |
| 1405 } | 1410 } |
| 1406 | 1411 |
| 1407 | 1412 |
| 1413 void BinaryOpIC::patch(Code* code) { |
| 1414 set_target(code); |
| 1415 } |
| 1416 |
| 1417 |
| 1418 void BinaryOpIC::Clear(Address address, Code* target) { |
| 1419 if (target->ic_state() == UNINITIALIZED) return; |
| 1420 |
| 1421 // At the end of a fast case stub there should be a reference to |
| 1422 // a corresponding UNINITIALIZED stub, so look for the last reloc info item. |
| 1423 RelocInfo* rinfo = NULL; |
| 1424 for (RelocIterator it(target, RelocInfo::kCodeTargetMask); |
| 1425 !it.done(); it.next()) { |
| 1426 rinfo = it.rinfo(); |
| 1427 } |
| 1428 |
| 1429 ASSERT(rinfo != NULL); |
| 1430 Code* uninit_stub = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
| 1431 ASSERT(uninit_stub->ic_state() == UNINITIALIZED && |
| 1432 uninit_stub->kind() == Code::BINARY_OP_IC); |
| 1433 SetTargetAtAddress(address, uninit_stub); |
| 1434 } |
| 1435 |
| 1436 |
| 1437 const char* BinaryOpIC::GetName(TypeInfo type_info) { |
| 1438 switch (type_info) { |
| 1439 case DEFAULT: return "Default"; |
| 1440 case GENERIC: return "Generic"; |
| 1441 case HEAP_NUMBERS: return "HeapNumbers"; |
| 1442 case STRINGS: return "Strings"; |
| 1443 default: return "Invalid"; |
| 1444 } |
| 1445 } |
| 1446 |
| 1447 |
| 1448 BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { |
| 1449 switch (type_info) { |
| 1450 // DEFAULT is mapped to UNINITIALIZED so that calls to DEFAULT stubs |
| 1451 // are not cleared at GC. |
| 1452 case DEFAULT: return UNINITIALIZED; |
| 1453 |
| 1454 // Could have mapped GENERIC to MONOMORPHIC just as well but MEGAMORPHIC is |
| 1455 // conceptually closer. |
| 1456 case GENERIC: return MEGAMORPHIC; |
| 1457 |
| 1458 default: return MONOMORPHIC; |
| 1459 } |
| 1460 } |
| 1461 |
| 1462 |
| 1463 BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Object* left, |
| 1464 Object* right) { |
| 1465 // Patching is never requested for the two smis. |
| 1466 ASSERT(!left->IsSmi() || !right->IsSmi()); |
| 1467 |
| 1468 if (left->IsNumber() && right->IsNumber()) { |
| 1469 return HEAP_NUMBERS; |
| 1470 } |
| 1471 |
| 1472 if (left->IsString() || right->IsString()) { |
| 1473 // Patching for fast string ADD makes sense even if only one of the |
| 1474 // arguments is a string. |
| 1475 return STRINGS; |
| 1476 } |
| 1477 |
| 1478 return GENERIC; |
| 1479 } |
| 1480 |
| 1481 |
| 1482 // defined in codegen-<arch>.cc |
| 1483 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info); |
| 1484 |
| 1485 |
| 1486 Object* BinaryOp_Patch(Arguments args) { |
| 1487 ASSERT(args.length() == 6); |
| 1488 |
| 1489 Handle<Object> left = args.at<Object>(0); |
| 1490 Handle<Object> right = args.at<Object>(1); |
| 1491 Handle<Object> result = args.at<Object>(2); |
| 1492 int key = Smi::cast(args[3])->value(); |
| 1493 #ifdef DEBUG |
| 1494 Token::Value op = static_cast<Token::Value>(Smi::cast(args[4])->value()); |
| 1495 BinaryOpIC::TypeInfo prev_type_info = |
| 1496 static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[5])->value()); |
| 1497 #endif // DEBUG |
| 1498 { HandleScope scope; |
| 1499 BinaryOpIC::TypeInfo type_info = BinaryOpIC::GetTypeInfo(*left, *right); |
| 1500 Handle<Code> code = GetBinaryOpStub(key, type_info); |
| 1501 if (!code.is_null()) { |
| 1502 BinaryOpIC ic; |
| 1503 ic.patch(*code); |
| 1504 #ifdef DEBUG |
| 1505 if (FLAG_trace_ic) { |
| 1506 PrintF("[BinaryOpIC (%s->%s)#%s]\n", |
| 1507 BinaryOpIC::GetName(prev_type_info), |
| 1508 BinaryOpIC::GetName(type_info), |
| 1509 Token::Name(op)); |
| 1510 } |
| 1511 #endif // DEBUG |
| 1512 } |
| 1513 } |
| 1514 |
| 1515 return *result; |
| 1516 } |
| 1517 |
| 1518 |
| 1408 static Address IC_utilities[] = { | 1519 static Address IC_utilities[] = { |
| 1409 #define ADDR(name) FUNCTION_ADDR(name), | 1520 #define ADDR(name) FUNCTION_ADDR(name), |
| 1410 IC_UTIL_LIST(ADDR) | 1521 IC_UTIL_LIST(ADDR) |
| 1411 NULL | 1522 NULL |
| 1412 #undef ADDR | 1523 #undef ADDR |
| 1413 }; | 1524 }; |
| 1414 | 1525 |
| 1415 | 1526 |
| 1416 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 1527 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
| 1417 return IC_utilities[id]; | 1528 return IC_utilities[id]; |
| 1418 } | 1529 } |
| 1419 | 1530 |
| 1420 | 1531 |
| 1421 } } // namespace v8::internal | 1532 } } // namespace v8::internal |
| OLD | NEW |