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 1087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1098 break; | 1098 break; |
1099 case DEBUG_STUB: | 1099 case DEBUG_STUB: |
1100 break; | 1100 break; |
1101 case GENERIC: | 1101 case GENERIC: |
1102 UNREACHABLE(); | 1102 UNREACHABLE(); |
1103 break; | 1103 break; |
1104 } | 1104 } |
1105 } | 1105 } |
1106 | 1106 |
1107 | 1107 |
| 1108 Handle<Code> LoadIC::SimpleFieldLoad(int offset, |
| 1109 bool inobject, |
| 1110 Representation representation) { |
| 1111 if (kind() == Code::LOAD_IC) { |
| 1112 LoadFieldStub stub(inobject, offset, representation); |
| 1113 return stub.GetCode(isolate()); |
| 1114 } else { |
| 1115 KeyedLoadFieldStub stub(inobject, offset, representation); |
| 1116 return stub.GetCode(isolate()); |
| 1117 } |
| 1118 } |
| 1119 |
1108 void LoadIC::UpdateCaches(LookupResult* lookup, | 1120 void LoadIC::UpdateCaches(LookupResult* lookup, |
1109 Handle<Object> object, | 1121 Handle<Object> object, |
1110 Handle<String> name) { | 1122 Handle<String> name) { |
1111 // TODO(verwaest): It would be nice to support loading fields from smis as | 1123 // TODO(verwaest): It would be nice to support loading fields from smis as |
1112 // well. For now just fail to update the cache. | 1124 // well. For now just fail to update the cache. |
1113 if (!object->IsHeapObject()) return; | 1125 if (!object->IsHeapObject()) return; |
1114 | 1126 |
1115 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); | 1127 Handle<HeapObject> receiver = Handle<HeapObject>::cast(object); |
1116 | 1128 |
1117 Handle<Code> code; | 1129 Handle<Code> code; |
1118 if (state() == UNINITIALIZED) { | 1130 if (state() == UNINITIALIZED) { |
1119 // This is the first time we execute this inline cache. | 1131 // This is the first time we execute this inline cache. |
1120 // Set the target to the pre monomorphic stub to delay | 1132 // Set the target to the pre monomorphic stub to delay |
1121 // setting the monomorphic state. | 1133 // setting the monomorphic state. |
1122 code = pre_monomorphic_stub(); | 1134 code = pre_monomorphic_stub(); |
1123 } else if (!lookup->IsCacheable()) { | 1135 } else if (!lookup->IsCacheable()) { |
1124 // Bail out if the result is not cacheable. | 1136 // Bail out if the result is not cacheable. |
1125 code = slow_stub(); | 1137 code = slow_stub(); |
1126 } else if (object->IsString() && | 1138 } else if (object->IsString() && |
1127 name->Equals(isolate()->heap()->length_string())) { | 1139 name->Equals(isolate()->heap()->length_string())) { |
1128 int length_index = String::kLengthOffset / kPointerSize; | 1140 int length_index = String::kLengthOffset / kPointerSize; |
1129 if (target()->is_load_stub()) { | 1141 code = SimpleFieldLoad(length_index); |
1130 LoadFieldStub stub(true, length_index, Representation::Tagged()); | |
1131 code = stub.GetCode(isolate()); | |
1132 } else { | |
1133 KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); | |
1134 code = stub.GetCode(isolate()); | |
1135 } | |
1136 } else if (!object->IsJSObject()) { | 1142 } else if (!object->IsJSObject()) { |
1137 // TODO(jkummerow): It would be nice to support non-JSObjects in | 1143 // TODO(jkummerow): It would be nice to support non-JSObjects in |
1138 // ComputeLoadHandler, then we wouldn't need to go generic here. | 1144 // ComputeLoadHandler, then we wouldn't need to go generic here. |
1139 code = slow_stub(); | 1145 code = slow_stub(); |
1140 } else if (!lookup->IsProperty()) { | 1146 } else if (!lookup->IsProperty()) { |
1141 code = kind() == Code::LOAD_IC | 1147 code = kind() == Code::LOAD_IC |
1142 ? isolate()->stub_cache()->ComputeLoadNonexistent( | 1148 ? isolate()->stub_cache()->ComputeLoadNonexistent( |
1143 name, Handle<JSObject>::cast(receiver)) | 1149 name, Handle<JSObject>::cast(receiver)) |
1144 : slow_stub(); | 1150 : slow_stub(); |
1145 } else { | 1151 } else { |
(...skipping 14 matching lines...) Expand all Loading... |
1160 | 1166 |
1161 Handle<Code> IC::ComputeHandler(LookupResult* lookup, | 1167 Handle<Code> IC::ComputeHandler(LookupResult* lookup, |
1162 Handle<JSObject> receiver, | 1168 Handle<JSObject> receiver, |
1163 Handle<String> name, | 1169 Handle<String> name, |
1164 Handle<Object> value) { | 1170 Handle<Object> value) { |
1165 Handle<Code> code = isolate()->stub_cache()->FindHandler( | 1171 Handle<Code> code = isolate()->stub_cache()->FindHandler( |
1166 name, receiver, kind()); | 1172 name, receiver, kind()); |
1167 if (!code.is_null()) return code; | 1173 if (!code.is_null()) return code; |
1168 | 1174 |
1169 code = CompileHandler(lookup, receiver, name, value); | 1175 code = CompileHandler(lookup, receiver, name, value); |
1170 if (code.is_null()) return slow_stub(); | |
1171 | 1176 |
1172 if (code->is_handler() && code->type() != Code::NORMAL) { | 1177 if (code->is_handler() && code->type() != Code::NORMAL) { |
1173 HeapObject::UpdateMapCodeCache(receiver, name, code); | 1178 HeapObject::UpdateMapCodeCache(receiver, name, code); |
1174 } | 1179 } |
1175 | 1180 |
1176 return code; | 1181 return code; |
1177 } | 1182 } |
1178 | 1183 |
1179 | 1184 |
1180 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, | 1185 Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
1181 Handle<JSObject> receiver, | 1186 Handle<JSObject> receiver, |
1182 Handle<String> name, | 1187 Handle<String> name, |
1183 Handle<Object> unused) { | 1188 Handle<Object> unused) { |
1184 Handle<JSObject> holder(lookup->holder()); | 1189 Handle<JSObject> holder(lookup->holder()); |
| 1190 LoadStubCompiler compiler(isolate(), kind()); |
| 1191 |
1185 switch (lookup->type()) { | 1192 switch (lookup->type()) { |
1186 case FIELD: | 1193 case FIELD: { |
1187 return isolate()->stub_cache()->ComputeLoadField( | 1194 PropertyIndex field = lookup->GetFieldIndex(); |
1188 name, receiver, holder, | 1195 if (receiver.is_identical_to(holder)) { |
1189 lookup->GetFieldIndex(), lookup->representation()); | 1196 return SimpleFieldLoad(field.translate(holder), |
| 1197 field.is_inobject(holder), |
| 1198 lookup->representation()); |
| 1199 } |
| 1200 return compiler.CompileLoadField( |
| 1201 receiver, holder, name, field, lookup->representation()); |
| 1202 } |
1190 case CONSTANT: { | 1203 case CONSTANT: { |
1191 Handle<Object> constant(lookup->GetConstant(), isolate()); | 1204 Handle<Object> constant(lookup->GetConstant(), isolate()); |
1192 // TODO(2803): Don't compute a stub for cons strings because they cannot | 1205 // TODO(2803): Don't compute a stub for cons strings because they cannot |
1193 // be embedded into code. | 1206 // be embedded into code. |
1194 if (constant->IsConsString()) return Handle<Code>::null(); | 1207 if (constant->IsConsString()) break; |
1195 return isolate()->stub_cache()->ComputeLoadConstant( | 1208 return compiler.CompileLoadConstant(receiver, holder, name, constant); |
1196 name, receiver, holder, constant); | |
1197 } | 1209 } |
1198 case NORMAL: | 1210 case NORMAL: |
| 1211 if (kind() != Code::LOAD_IC) break; |
1199 if (holder->IsGlobalObject()) { | 1212 if (holder->IsGlobalObject()) { |
1200 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); | 1213 Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
1201 Handle<PropertyCell> cell( | 1214 Handle<PropertyCell> cell( |
1202 global->GetPropertyCell(lookup), isolate()); | 1215 global->GetPropertyCell(lookup), isolate()); |
| 1216 // TODO(verwaest): Turn into a handler. |
1203 return isolate()->stub_cache()->ComputeLoadGlobal( | 1217 return isolate()->stub_cache()->ComputeLoadGlobal( |
1204 name, receiver, global, cell, lookup->IsDontDelete()); | 1218 name, receiver, global, cell, lookup->IsDontDelete()); |
1205 } | 1219 } |
1206 // There is only one shared stub for loading normalized | 1220 // There is only one shared stub for loading normalized |
1207 // properties. It does not traverse the prototype chain, so the | 1221 // properties. It does not traverse the prototype chain, so the |
1208 // property must be found in the receiver for the stub to be | 1222 // property must be found in the receiver for the stub to be |
1209 // applicable. | 1223 // applicable. |
1210 if (!holder.is_identical_to(receiver)) break; | 1224 if (!holder.is_identical_to(receiver)) break; |
1211 return isolate()->stub_cache()->ComputeLoadNormal(name, receiver); | 1225 return isolate()->builtins()->LoadIC_Normal(); |
1212 case CALLBACKS: { | 1226 case CALLBACKS: { |
1213 { | 1227 // Use simple field loads for some well-known callback properties. |
1214 // Use simple field loads for some well-known callback properties. | 1228 int object_offset; |
1215 int object_offset; | 1229 Handle<Map> map(receiver->map()); |
1216 Handle<Map> map(receiver->map()); | 1230 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { |
1217 if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { | 1231 PropertyIndex index = |
1218 PropertyIndex index = | 1232 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); |
1219 PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); | 1233 return compiler.CompileLoadField( |
1220 return isolate()->stub_cache()->ComputeLoadField( | 1234 receiver, receiver, name, index, Representation::Tagged()); |
1221 name, receiver, receiver, index, Representation::Tagged()); | |
1222 } | |
1223 } | 1235 } |
1224 | 1236 |
1225 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1237 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
1226 if (callback->IsExecutableAccessorInfo()) { | 1238 if (callback->IsExecutableAccessorInfo()) { |
1227 Handle<ExecutableAccessorInfo> info = | 1239 Handle<ExecutableAccessorInfo> info = |
1228 Handle<ExecutableAccessorInfo>::cast(callback); | 1240 Handle<ExecutableAccessorInfo>::cast(callback); |
1229 if (v8::ToCData<Address>(info->getter()) == 0) break; | 1241 if (v8::ToCData<Address>(info->getter()) == 0) break; |
1230 if (!info->IsCompatibleReceiver(*receiver)) break; | 1242 if (!info->IsCompatibleReceiver(*receiver)) break; |
1231 return isolate()->stub_cache()->ComputeLoadCallback( | 1243 return compiler.CompileLoadCallback(receiver, holder, name, info); |
1232 name, receiver, holder, info); | |
1233 } else if (callback->IsAccessorPair()) { | 1244 } else if (callback->IsAccessorPair()) { |
1234 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), | 1245 Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), |
1235 isolate()); | 1246 isolate()); |
1236 if (!getter->IsJSFunction()) break; | 1247 if (!getter->IsJSFunction()) break; |
1237 if (holder->IsGlobalObject()) break; | 1248 if (holder->IsGlobalObject()) break; |
1238 if (!holder->HasFastProperties()) break; | 1249 if (!holder->HasFastProperties()) break; |
1239 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | 1250 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
1240 CallOptimization call_optimization(function); | 1251 CallOptimization call_optimization(function); |
1241 if (call_optimization.is_simple_api_call() && | 1252 if (call_optimization.is_simple_api_call() && |
1242 call_optimization.IsCompatibleReceiver(*receiver)) { | 1253 call_optimization.IsCompatibleReceiver(*receiver)) { |
1243 return isolate()->stub_cache()->ComputeLoadCallback( | 1254 return compiler.CompileLoadCallback( |
1244 name, receiver, holder, call_optimization); | 1255 receiver, holder, name, call_optimization); |
1245 } | 1256 } |
1246 return isolate()->stub_cache()->ComputeLoadViaGetter( | 1257 return compiler.CompileLoadViaGetter(receiver, holder, name, function); |
1247 name, receiver, holder, function); | |
1248 } | 1258 } |
1249 // TODO(dcarney): Handle correctly. | 1259 // TODO(dcarney): Handle correctly. |
1250 if (callback->IsDeclaredAccessorInfo()) break; | 1260 if (callback->IsDeclaredAccessorInfo()) break; |
1251 ASSERT(callback->IsForeign()); | 1261 ASSERT(callback->IsForeign()); |
1252 // No IC support for old-style native accessors. | 1262 // No IC support for old-style native accessors. |
1253 break; | 1263 break; |
1254 } | 1264 } |
1255 case INTERCEPTOR: | 1265 case INTERCEPTOR: |
1256 ASSERT(HasInterceptorGetter(*holder)); | 1266 ASSERT(HasInterceptorGetter(*holder)); |
1257 return isolate()->stub_cache()->ComputeLoadInterceptor( | 1267 return compiler.CompileLoadInterceptor(receiver, holder, name); |
1258 name, receiver, holder); | |
1259 default: | 1268 default: |
1260 break; | 1269 break; |
1261 } | 1270 } |
1262 return Handle<Code>::null(); | 1271 |
| 1272 return slow_stub(); |
1263 } | 1273 } |
1264 | 1274 |
1265 | 1275 |
1266 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { | 1276 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
1267 // This helper implements a few common fast cases for converting | 1277 // This helper implements a few common fast cases for converting |
1268 // non-smi keys of keyed loads/stores to a smi or a string. | 1278 // non-smi keys of keyed loads/stores to a smi or a string. |
1269 if (key->IsHeapNumber()) { | 1279 if (key->IsHeapNumber()) { |
1270 double value = Handle<HeapNumber>::cast(key)->value(); | 1280 double value = Handle<HeapNumber>::cast(key)->value(); |
1271 if (std::isnan(value)) { | 1281 if (std::isnan(value)) { |
1272 key = isolate->factory()->nan_string(); | 1282 key = isolate->factory()->nan_string(); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1384 ASSERT(!stub.is_null()); | 1394 ASSERT(!stub.is_null()); |
1385 set_target(*stub); | 1395 set_target(*stub); |
1386 TRACE_IC("LoadIC", key); | 1396 TRACE_IC("LoadIC", key); |
1387 } | 1397 } |
1388 | 1398 |
1389 | 1399 |
1390 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); | 1400 return Runtime::GetObjectPropertyOrFail(isolate(), object, key); |
1391 } | 1401 } |
1392 | 1402 |
1393 | 1403 |
1394 Handle<Code> KeyedLoadIC::CompileHandler(LookupResult* lookup, | |
1395 Handle<JSObject> receiver, | |
1396 Handle<String> name, | |
1397 Handle<Object> value) { | |
1398 // Compute a monomorphic stub. | |
1399 Handle<JSObject> holder(lookup->holder(), isolate()); | |
1400 switch (lookup->type()) { | |
1401 case FIELD: | |
1402 return isolate()->stub_cache()->ComputeKeyedLoadField( | |
1403 name, receiver, holder, | |
1404 lookup->GetFieldIndex(), lookup->representation()); | |
1405 case CONSTANT: { | |
1406 Handle<Object> constant(lookup->GetConstant(), isolate()); | |
1407 // TODO(2803): Don't compute a stub for cons strings because they cannot | |
1408 // be embedded into code. | |
1409 if (constant->IsConsString()) return Handle<Code>::null(); | |
1410 return isolate()->stub_cache()->ComputeKeyedLoadConstant( | |
1411 name, receiver, holder, constant); | |
1412 } | |
1413 case CALLBACKS: { | |
1414 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate()); | |
1415 // TODO(dcarney): Handle DeclaredAccessorInfo correctly. | |
1416 if (callback_object->IsExecutableAccessorInfo()) { | |
1417 Handle<ExecutableAccessorInfo> callback = | |
1418 Handle<ExecutableAccessorInfo>::cast(callback_object); | |
1419 if (v8::ToCData<Address>(callback->getter()) == 0) break; | |
1420 if (!callback->IsCompatibleReceiver(*receiver)) break; | |
1421 return isolate()->stub_cache()->ComputeKeyedLoadCallback( | |
1422 name, receiver, holder, callback); | |
1423 } else if (callback_object->IsAccessorPair()) { | |
1424 Handle<Object> getter( | |
1425 Handle<AccessorPair>::cast(callback_object)->getter(), | |
1426 isolate()); | |
1427 if (!getter->IsJSFunction()) break; | |
1428 if (holder->IsGlobalObject()) break; | |
1429 if (!holder->HasFastProperties()) break; | |
1430 Handle<JSFunction> function = Handle<JSFunction>::cast(getter); | |
1431 CallOptimization call_optimization(function); | |
1432 if (call_optimization.is_simple_api_call() && | |
1433 call_optimization.IsCompatibleReceiver(*receiver)) { | |
1434 return isolate()->stub_cache()->ComputeKeyedLoadCallback( | |
1435 name, receiver, holder, call_optimization); | |
1436 } | |
1437 } | |
1438 break; | |
1439 } | |
1440 case INTERCEPTOR: | |
1441 ASSERT(HasInterceptorGetter(lookup->holder())); | |
1442 return isolate()->stub_cache()->ComputeKeyedLoadInterceptor( | |
1443 name, receiver, holder); | |
1444 default: | |
1445 // Always rewrite to the generic case so that we do not | |
1446 // repeatedly try to rewrite. | |
1447 return generic_stub(); | |
1448 } | |
1449 return Handle<Code>::null(); | |
1450 } | |
1451 | |
1452 | |
1453 static bool LookupForWrite(Handle<JSObject> receiver, | 1404 static bool LookupForWrite(Handle<JSObject> receiver, |
1454 Handle<String> name, | 1405 Handle<String> name, |
1455 Handle<Object> value, | 1406 Handle<Object> value, |
1456 LookupResult* lookup, | 1407 LookupResult* lookup, |
1457 IC* ic) { | 1408 IC* ic) { |
1458 Handle<JSObject> holder = receiver; | 1409 Handle<JSObject> holder = receiver; |
1459 receiver->Lookup(*name, lookup); | 1410 receiver->Lookup(*name, lookup); |
1460 if (lookup->IsFound()) { | 1411 if (lookup->IsFound()) { |
1461 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; | 1412 if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false; |
1462 | 1413 |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1640 PatchCache(receiver, name, code); | 1591 PatchCache(receiver, name, code); |
1641 TRACE_IC("StoreIC", name); | 1592 TRACE_IC("StoreIC", name); |
1642 } | 1593 } |
1643 | 1594 |
1644 | 1595 |
1645 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, | 1596 Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
1646 Handle<JSObject> receiver, | 1597 Handle<JSObject> receiver, |
1647 Handle<String> name, | 1598 Handle<String> name, |
1648 Handle<Object> value) { | 1599 Handle<Object> value) { |
1649 Handle<JSObject> holder(lookup->holder()); | 1600 Handle<JSObject> holder(lookup->holder()); |
| 1601 StoreStubCompiler compiler(isolate(), strict_mode(), kind()); |
1650 switch (lookup->type()) { | 1602 switch (lookup->type()) { |
1651 case FIELD: | 1603 case FIELD: |
1652 return isolate()->stub_cache()->ComputeStoreField( | 1604 return compiler.CompileStoreField(receiver, lookup, name); |
1653 name, receiver, lookup, strict_mode()); | 1605 case TRANSITION: { |
| 1606 // Explicitly pass in the receiver map since LookupForWrite may have |
| 1607 // stored something else than the receiver in the holder. |
| 1608 Handle<Map> transition( |
| 1609 lookup->GetTransitionTarget(receiver->map()), isolate()); |
| 1610 int descriptor = transition->LastAdded(); |
| 1611 |
| 1612 DescriptorArray* target_descriptors = transition->instance_descriptors(); |
| 1613 PropertyDetails details = target_descriptors->GetDetails(descriptor); |
| 1614 |
| 1615 if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
| 1616 |
| 1617 return compiler.CompileStoreTransition( |
| 1618 receiver, lookup, transition, name); |
| 1619 } |
1654 case NORMAL: | 1620 case NORMAL: |
| 1621 if (kind() == Code::KEYED_STORE_IC) break; |
1655 if (receiver->IsGlobalObject()) { | 1622 if (receiver->IsGlobalObject()) { |
1656 // The stub generated for the global object picks the value directly | 1623 // The stub generated for the global object picks the value directly |
1657 // from the property cell. So the property must be directly on the | 1624 // from the property cell. So the property must be directly on the |
1658 // global object. | 1625 // global object. |
1659 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); | 1626 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
1660 Handle<PropertyCell> cell( | 1627 Handle<PropertyCell> cell( |
1661 global->GetPropertyCell(lookup), isolate()); | 1628 global->GetPropertyCell(lookup), isolate()); |
| 1629 // TODO(verwaest): Turn into a handler. |
1662 return isolate()->stub_cache()->ComputeStoreGlobal( | 1630 return isolate()->stub_cache()->ComputeStoreGlobal( |
1663 name, global, cell, value, strict_mode()); | 1631 name, global, cell, value, strict_mode()); |
1664 } | 1632 } |
1665 ASSERT(holder.is_identical_to(receiver)); | 1633 ASSERT(holder.is_identical_to(receiver)); |
1666 return isolate()->stub_cache()->ComputeStoreNormal(strict_mode()); | 1634 return strict_mode() == kStrictMode |
| 1635 ? isolate()->builtins()->StoreIC_Normal_Strict() |
| 1636 : isolate()->builtins()->StoreIC_Normal(); |
1667 case CALLBACKS: { | 1637 case CALLBACKS: { |
| 1638 if (kind() == Code::KEYED_STORE_IC) break; |
1668 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); | 1639 Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
1669 if (callback->IsExecutableAccessorInfo()) { | 1640 if (callback->IsExecutableAccessorInfo()) { |
1670 Handle<ExecutableAccessorInfo> info = | 1641 Handle<ExecutableAccessorInfo> info = |
1671 Handle<ExecutableAccessorInfo>::cast(callback); | 1642 Handle<ExecutableAccessorInfo>::cast(callback); |
1672 if (v8::ToCData<Address>(info->setter()) == 0) break; | 1643 if (v8::ToCData<Address>(info->setter()) == 0) break; |
1673 if (!holder->HasFastProperties()) break; | 1644 if (!holder->HasFastProperties()) break; |
1674 if (!info->IsCompatibleReceiver(*receiver)) break; | 1645 if (!info->IsCompatibleReceiver(*receiver)) break; |
1675 return isolate()->stub_cache()->ComputeStoreCallback( | 1646 return compiler.CompileStoreCallback(receiver, holder, name, info); |
1676 name, receiver, holder, info, strict_mode()); | |
1677 } else if (callback->IsAccessorPair()) { | 1647 } else if (callback->IsAccessorPair()) { |
1678 Handle<Object> setter( | 1648 Handle<Object> setter( |
1679 Handle<AccessorPair>::cast(callback)->setter(), isolate()); | 1649 Handle<AccessorPair>::cast(callback)->setter(), isolate()); |
1680 if (!setter->IsJSFunction()) break; | 1650 if (!setter->IsJSFunction()) break; |
1681 if (holder->IsGlobalObject()) break; | 1651 if (holder->IsGlobalObject()) break; |
1682 if (!holder->HasFastProperties()) break; | 1652 if (!holder->HasFastProperties()) break; |
1683 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); | 1653 Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
1684 CallOptimization call_optimization(function); | 1654 CallOptimization call_optimization(function); |
1685 if (call_optimization.is_simple_api_call() && | 1655 if (call_optimization.is_simple_api_call() && |
1686 call_optimization.IsCompatibleReceiver(*receiver)) { | 1656 call_optimization.IsCompatibleReceiver(*receiver)) { |
1687 return isolate()->stub_cache()->ComputeStoreCallback( | 1657 return compiler.CompileStoreCallback( |
1688 name, receiver, holder, call_optimization, strict_mode()); | 1658 receiver, holder, name, call_optimization); |
1689 } | 1659 } |
1690 return isolate()->stub_cache()->ComputeStoreViaSetter( | 1660 return compiler.CompileStoreViaSetter( |
1691 name, receiver, holder, Handle<JSFunction>::cast(setter), | 1661 receiver, holder, name, Handle<JSFunction>::cast(setter)); |
1692 strict_mode()); | |
1693 } | 1662 } |
1694 // TODO(dcarney): Handle correctly. | 1663 // TODO(dcarney): Handle correctly. |
1695 if (callback->IsDeclaredAccessorInfo()) break; | 1664 if (callback->IsDeclaredAccessorInfo()) break; |
1696 ASSERT(callback->IsForeign()); | 1665 ASSERT(callback->IsForeign()); |
1697 // No IC support for old-style native accessors. | 1666 // No IC support for old-style native accessors. |
1698 break; | 1667 break; |
1699 } | 1668 } |
1700 case INTERCEPTOR: | 1669 case INTERCEPTOR: |
| 1670 if (kind() == Code::KEYED_STORE_IC) break; |
1701 ASSERT(HasInterceptorSetter(*receiver)); | 1671 ASSERT(HasInterceptorSetter(*receiver)); |
1702 return isolate()->stub_cache()->ComputeStoreInterceptor( | 1672 return compiler.CompileStoreInterceptor(receiver, name); |
1703 name, receiver, strict_mode()); | |
1704 case CONSTANT: | 1673 case CONSTANT: |
1705 break; | 1674 break; |
1706 case TRANSITION: { | |
1707 // Explicitly pass in the receiver map since LookupForWrite may have | |
1708 // stored something else than the receiver in the holder. | |
1709 Handle<Map> transition( | |
1710 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
1711 int descriptor = transition->LastAdded(); | |
1712 | |
1713 DescriptorArray* target_descriptors = transition->instance_descriptors(); | |
1714 PropertyDetails details = target_descriptors->GetDetails(descriptor); | |
1715 | |
1716 if (details.type() == CALLBACKS || details.attributes() != NONE) break; | |
1717 | |
1718 return isolate()->stub_cache()->ComputeStoreTransition( | |
1719 name, receiver, lookup, transition, strict_mode()); | |
1720 } | |
1721 case NONEXISTENT: | 1675 case NONEXISTENT: |
1722 case HANDLER: | 1676 case HANDLER: |
1723 UNREACHABLE(); | 1677 UNREACHABLE(); |
1724 break; | 1678 break; |
1725 } | 1679 } |
1726 return Handle<Code>::null(); | 1680 return slow_stub(); |
1727 } | 1681 } |
1728 | 1682 |
1729 | 1683 |
1730 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, | 1684 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver, |
1731 KeyedAccessStoreMode store_mode) { | 1685 KeyedAccessStoreMode store_mode) { |
1732 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS | 1686 // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS |
1733 // via megamorphic stubs, since they don't have a map in their relocation info | 1687 // via megamorphic stubs, since they don't have a map in their relocation info |
1734 // and so the stubs can't be harvested for the object needed for a map check. | 1688 // and so the stubs can't be harvested for the object needed for a map check. |
1735 if (target()->type() != Code::NORMAL) { | 1689 if (target()->type() != Code::NORMAL) { |
1736 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); | 1690 TRACE_GENERIC_IC(isolate(), "KeyedIC", "non-NORMAL target type"); |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2027 ASSERT(!stub.is_null()); | 1981 ASSERT(!stub.is_null()); |
2028 set_target(*stub); | 1982 set_target(*stub); |
2029 TRACE_IC("StoreIC", key); | 1983 TRACE_IC("StoreIC", key); |
2030 } | 1984 } |
2031 | 1985 |
2032 return Runtime::SetObjectPropertyOrFail( | 1986 return Runtime::SetObjectPropertyOrFail( |
2033 isolate(), object , key, value, NONE, strict_mode()); | 1987 isolate(), object , key, value, NONE, strict_mode()); |
2034 } | 1988 } |
2035 | 1989 |
2036 | 1990 |
2037 Handle<Code> KeyedStoreIC::CompileHandler(LookupResult* lookup, | |
2038 Handle<JSObject> receiver, | |
2039 Handle<String> name, | |
2040 Handle<Object> value) { | |
2041 // If the property has a non-field type allowing map transitions | |
2042 // where there is extra room in the object, we leave the IC in its | |
2043 // current state. | |
2044 switch (lookup->type()) { | |
2045 case FIELD: | |
2046 return isolate()->stub_cache()->ComputeKeyedStoreField( | |
2047 name, receiver, lookup, strict_mode()); | |
2048 case TRANSITION: { | |
2049 // Explicitly pass in the receiver map since LookupForWrite may have | |
2050 // stored something else than the receiver in the holder. | |
2051 Handle<Map> transition( | |
2052 lookup->GetTransitionTarget(receiver->map()), isolate()); | |
2053 int descriptor = transition->LastAdded(); | |
2054 | |
2055 DescriptorArray* target_descriptors = transition->instance_descriptors(); | |
2056 PropertyDetails details = target_descriptors->GetDetails(descriptor); | |
2057 | |
2058 if (details.type() != CALLBACKS && details.attributes() == NONE) { | |
2059 return isolate()->stub_cache()->ComputeKeyedStoreTransition( | |
2060 name, receiver, lookup, transition, strict_mode()); | |
2061 } | |
2062 // fall through. | |
2063 } | |
2064 case NORMAL: | |
2065 case CONSTANT: | |
2066 case CALLBACKS: | |
2067 case INTERCEPTOR: | |
2068 // Always rewrite to the generic case so that we do not | |
2069 // repeatedly try to rewrite. | |
2070 return generic_stub(); | |
2071 case HANDLER: | |
2072 case NONEXISTENT: | |
2073 UNREACHABLE(); | |
2074 break; | |
2075 } | |
2076 return Handle<Code>::null(); | |
2077 } | |
2078 | |
2079 | |
2080 #undef TRACE_IC | 1991 #undef TRACE_IC |
2081 | 1992 |
2082 | 1993 |
2083 // ---------------------------------------------------------------------------- | 1994 // ---------------------------------------------------------------------------- |
2084 // Static IC stub generators. | 1995 // Static IC stub generators. |
2085 // | 1996 // |
2086 | 1997 |
2087 // Used from ic-<arch>.cc. | 1998 // Used from ic-<arch>.cc. |
2088 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { | 1999 RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { |
2089 HandleScope scope(isolate); | 2000 HandleScope scope(isolate); |
(...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2802 #undef ADDR | 2713 #undef ADDR |
2803 }; | 2714 }; |
2804 | 2715 |
2805 | 2716 |
2806 Address IC::AddressFromUtilityId(IC::UtilityId id) { | 2717 Address IC::AddressFromUtilityId(IC::UtilityId id) { |
2807 return IC_utilities[id]; | 2718 return IC_utilities[id]; |
2808 } | 2719 } |
2809 | 2720 |
2810 | 2721 |
2811 } } // namespace v8::internal | 2722 } } // namespace v8::internal |
OLD | NEW |